
import { __decorate, __param } from '../../../../../../external/tslib/tslib.es6.js';
import { localize } from '../../../nls.js';
import { getActiveWindow, addDisposableListener } from '../../../base/browser/dom.js';
import { createFastDomNode } from '../../../base/browser/fastDomNode.js';
import { BugIndicatingError } from '../../../base/common/errors.js';
import { Disposable } from '../../../base/common/lifecycle.js';
import { observableValue } from '../../../base/common/observableInternal/base.js';
import '../../../base/common/arrays.js';
import { Event } from '../../../base/common/event.js';
import '../../../base/common/observableInternal/autorun.js';
import '../../../base/common/observableInternal/derived.js';
import '../../../base/common/cancellation.js';
import { runOnChange } from '../../../base/common/observableInternal/utils.js';
import { IInstantiationService } from '../../../platform/instantiation/common/instantiation.js';
import { TextureAtlas } from './atlas/textureAtlas.js';
import { IConfigurationService } from '../../../platform/configuration/common/configuration.service.js';
import '../../../platform/notification/common/notification.js';
import { INotificationService } from '../../../platform/notification/common/notification.service.js';
import { GPULifecycle } from './gpuDisposable.js';
import { ensureNonNullable, observeDevicePixelDimensions } from './gpuUtils.js';
import { RectangleRenderer } from './rectangleRenderer.js';
import { DecorationCssRuleExtractor } from './decorationCssRuleExtractor.js';
import { InlineDecorationType } from '../../common/viewModel.js';
import Severity$1 from '../../../base/common/severity.js';

var ViewGpuContext_1;
var GpuRenderLimits;
(function (GpuRenderLimits) {
    GpuRenderLimits[GpuRenderLimits["maxGpuLines"] = 3000] = "maxGpuLines";
    GpuRenderLimits[GpuRenderLimits["maxGpuCols"] = 200] = "maxGpuCols";
})(GpuRenderLimits || (GpuRenderLimits = {}));
let ViewGpuContext = class ViewGpuContext extends Disposable {
    static { ViewGpuContext_1 = this; }
    static { this._decorationCssRuleExtractor = ( new DecorationCssRuleExtractor()); }
    static get decorationCssRuleExtractor() {
        return ViewGpuContext_1._decorationCssRuleExtractor;
    }
    static get atlas() {
        if (!ViewGpuContext_1._atlas) {
            throw ( new BugIndicatingError('Cannot call ViewGpuContext.textureAtlas before device is resolved'));
        }
        return ViewGpuContext_1._atlas;
    }
    get atlas() {
        return ViewGpuContext_1.atlas;
    }
    constructor(context, _instantiationService, _notificationService, configurationService) {
        super();
        this._instantiationService = _instantiationService;
        this._notificationService = _notificationService;
        this.configurationService = configurationService;
        this.maxGpuLines = GpuRenderLimits.maxGpuLines;
        this.maxGpuCols = GpuRenderLimits.maxGpuCols;
        this.canvas = createFastDomNode(document.createElement('canvas'));
        this.canvas.setClassName('editorCanvas');
        this._register(Event.runAndSubscribe(configurationService.onDidChangeConfiguration, e => {
            if (!e || e.affectsConfiguration('editor.scrollbar.verticalScrollbarSize')) {
                const verticalScrollbarSize = configurationService.getValue('editor').scrollbar?.verticalScrollbarSize ?? 14;
                this.canvas.domNode.style.boxSizing = 'border-box';
                this.canvas.domNode.style.paddingRight = `${verticalScrollbarSize}px`;
            }
        }));
        this.ctx = ensureNonNullable(this.canvas.domNode.getContext('webgpu'));
        this.device = GPULifecycle.requestDevice((message) => {
            const choices = [{
                    label: ( localize(144, "Use DOM-based rendering")),
                    run: () => this.configurationService.updateValue('editor.experimentalGpuAcceleration', 'off'),
                }];
            this._notificationService.prompt(Severity$1.Warning, message, choices);
        }).then(ref => this._register(ref).object);
        this.device.then(device => {
            if (!ViewGpuContext_1._atlas) {
                ViewGpuContext_1._atlas = this._instantiationService.createInstance(TextureAtlas, device.limits.maxTextureDimension2D, undefined);
            }
        });
        this.rectangleRenderer = this._instantiationService.createInstance(RectangleRenderer, context, this.canvas.domNode, this.ctx, this.device);
        const dprObs = observableValue(this, getActiveWindow().devicePixelRatio);
        this._register(addDisposableListener(getActiveWindow(), 'resize', () => {
            dprObs.set(getActiveWindow().devicePixelRatio, undefined);
        }));
        this.devicePixelRatio = dprObs;
        this._register(runOnChange(this.devicePixelRatio, () => ViewGpuContext_1.atlas?.clear()));
        const canvasDevicePixelDimensions = observableValue(this, { width: this.canvas.domNode.width, height: this.canvas.domNode.height });
        this._register(observeDevicePixelDimensions(this.canvas.domNode, getActiveWindow(), (width, height) => {
            this.canvas.domNode.width = width;
            this.canvas.domNode.height = height;
            canvasDevicePixelDimensions.set({ width, height }, undefined);
        }));
        this.canvasDevicePixelDimensions = canvasDevicePixelDimensions;
    }
    canRender(options, viewportData, lineNumber) {
        const data = viewportData.getViewLineRenderingData(lineNumber);
        if (data.containsRTL ||
            data.maxColumn > GpuRenderLimits.maxGpuCols ||
            data.continuesWithWrappedLine ||
            lineNumber >= GpuRenderLimits.maxGpuLines) {
            return false;
        }
        if (data.inlineDecorations.length > 0) {
            let supported = true;
            for (const decoration of data.inlineDecorations) {
                if (decoration.type !== InlineDecorationType.Regular) {
                    supported = false;
                    break;
                }
                const styleRules = ViewGpuContext_1._decorationCssRuleExtractor.getStyleRules(this.canvas.domNode, decoration.inlineClassName);
                supported &&= styleRules.every(rule => {
                    if (rule.selectorText.includes(':')) {
                        return false;
                    }
                    for (const r of rule.style) {
                        if (!gpuSupportedDecorationCssRules.includes(r)) {
                            return false;
                        }
                    }
                    return true;
                });
                if (!supported) {
                    break;
                }
            }
            return supported;
        }
        return true;
    }
    canRenderDetailed(options, viewportData, lineNumber) {
        const data = viewportData.getViewLineRenderingData(lineNumber);
        const reasons = [];
        if (data.containsRTL) {
            reasons.push('containsRTL');
        }
        if (data.maxColumn > GpuRenderLimits.maxGpuCols) {
            reasons.push('maxColumn > maxGpuCols');
        }
        if (data.continuesWithWrappedLine) {
            reasons.push('continuesWithWrappedLine');
        }
        if (data.inlineDecorations.length > 0) {
            let supported = true;
            const problemTypes = [];
            const problemSelectors = [];
            const problemRules = [];
            for (const decoration of data.inlineDecorations) {
                if (decoration.type !== InlineDecorationType.Regular) {
                    problemTypes.push(decoration.type);
                    supported = false;
                    continue;
                }
                const styleRules = ViewGpuContext_1._decorationCssRuleExtractor.getStyleRules(this.canvas.domNode, decoration.inlineClassName);
                supported &&= styleRules.every(rule => {
                    if (rule.selectorText.includes(':')) {
                        problemSelectors.push(rule.selectorText);
                        return false;
                    }
                    for (const r of rule.style) {
                        if (!gpuSupportedDecorationCssRules.includes(r)) {
                            problemRules.push(r);
                            return false;
                        }
                    }
                    return true;
                });
                if (!supported) {
                    continue;
                }
            }
            if (problemTypes.length > 0) {
                reasons.push(`inlineDecorations with unsupported types (${( problemTypes.map(e => `\`${e}\``)).join(', ')})`);
            }
            if (problemRules.length > 0) {
                reasons.push(`inlineDecorations with unsupported CSS rules (${( problemRules.map(e => `\`${e}\``)).join(', ')})`);
            }
            if (problemSelectors.length > 0) {
                reasons.push(`inlineDecorations with unsupported CSS selectors (${( problemSelectors.map(e => `\`${e}\``)).join(', ')})`);
            }
        }
        if (lineNumber >= GpuRenderLimits.maxGpuLines) {
            reasons.push('lineNumber >= maxGpuLines');
        }
        return reasons;
    }
};
ViewGpuContext = ViewGpuContext_1 = ( __decorate([
    ( __param(1, IInstantiationService)),
    ( __param(2, INotificationService)),
    ( __param(3, IConfigurationService))
], ViewGpuContext));
const gpuSupportedDecorationCssRules = [
    'color',
];

export { ViewGpuContext };
