提交 742f017f 编写于 作者: A Alex Dima

Fixes #6151: Avoid having the browser scale up the overview ruler canvas

上级 06b47ae5
......@@ -14,9 +14,12 @@ class ZoomManager {
public static INSTANCE = new ZoomManager();
private _zoomLevel: number = 0;
private _pixelRatioCache: number = 0;
private _pixelRatioComputed: boolean = false;
private _onDidChangeZoomLevel: Emitter<number> = new Emitter<number>();
public onDidChangeZoomLevel:Event<number> = this._onDidChangeZoomLevel.event;
public getZoomLevel(): number {
return this._zoomLevel;
}
......@@ -27,13 +30,36 @@ class ZoomManager {
}
this._zoomLevel = zoomLevel;
this._pixelRatioComputed = false;
this._onDidChangeZoomLevel.fire(this._zoomLevel);
}
public getPixelRatio(): number {
if (!this._pixelRatioComputed) {
this._pixelRatioCache = this._computePixelRatio();
this._pixelRatioComputed = true;
}
return this._pixelRatioCache;
}
private _computePixelRatio(): number {
let ctx = document.createElement('canvas').getContext('2d');
let dpr = window.devicePixelRatio || 1;
let bsr = (<any>ctx).webkitBackingStorePixelRatio ||
(<any>ctx).mozBackingStorePixelRatio ||
(<any>ctx).msBackingStorePixelRatio ||
(<any>ctx).oBackingStorePixelRatio ||
(<any>ctx).backingStorePixelRatio || 1;
return dpr / bsr;
}
}
export function getZoomLevel(): number {
return ZoomManager.INSTANCE.getZoomLevel();
}
export function getPixelRatio(): number {
return ZoomManager.INSTANCE.getPixelRatio();
}
export function setZoomLevel(zoomLevel:number): void {
ZoomManager.INSTANCE.setZoomLevel(zoomLevel);
}
......
......@@ -359,108 +359,14 @@ export interface IEditorContributionDescriptor {
createInstance(instantiationService:IInstantiationService, editor:ICodeEditor): editorCommon.IEditorContribution;
}
export class ColorZone {
_colorZoneBrand: void;
from: number;
to: number;
colorId: number;
position: editorCommon.OverviewRulerLane;
constructor(from:number, to:number, colorId:number, position: editorCommon.OverviewRulerLane) {
this.from = from|0;
this.to = to|0;
this.colorId = colorId|0;
this.position = position|0;
}
}
/**
* A zone in the overview ruler
*/
export class OverviewRulerZone {
_overviewRulerZoneBrand: void;
startLineNumber: number;
endLineNumber: number;
position: editorCommon.OverviewRulerLane;
forceHeight: number;
private _color: string;
private _darkColor: string;
private _colorZones: ColorZone[];
constructor(
startLineNumber: number, endLineNumber: number,
position: editorCommon.OverviewRulerLane,
forceHeight: number,
color: string, darkColor: string
) {
this.startLineNumber = startLineNumber;
this.endLineNumber = endLineNumber;
this.position = position;
this.forceHeight = forceHeight;
this._color = color;
this._darkColor = darkColor;
this._colorZones = null;
}
public getColor(useDarkColor:boolean): string {
if (useDarkColor) {
return this._darkColor;
}
return this._color;
}
public equals(other:OverviewRulerZone): boolean {
return (
this.startLineNumber === other.startLineNumber
&& this.endLineNumber === other.endLineNumber
&& this.position === other.position
&& this.forceHeight === other.forceHeight
&& this._color === other._color
&& this._darkColor === other._darkColor
);
}
public compareTo(other:OverviewRulerZone): number {
if (this.startLineNumber === other.startLineNumber) {
if (this.endLineNumber === other.endLineNumber) {
if (this.forceHeight === other.forceHeight) {
if (this.position === other.position) {
if (this._darkColor === other._darkColor) {
if (this._color === other._color) {
return 0;
}
return this._color < other._color ? -1 : 1;
}
return this._darkColor < other._darkColor ? -1 : 1;
}
return this.position - other.position;
}
return this.forceHeight - other.forceHeight;
}
return this.endLineNumber - other.endLineNumber;
}
return this.startLineNumber - other.startLineNumber;
}
public setColorZones(colorZones:ColorZone[]): void {
this._colorZones = colorZones;
}
public getColorZones(): ColorZone[] {
return this._colorZones;
}
}
/**
* An overview ruler
*/
export interface IOverviewRuler {
getDomNode(): HTMLElement;
dispose(): void;
setZones(zones:OverviewRulerZone[]): void;
setZones(zones:editorCommon.OverviewRulerZone[]): void;
setLayout(position:editorCommon.OverviewRulerPosition): void;
}
/**
......
......@@ -6,7 +6,6 @@
import * as themes from 'vs/platform/theme/common/themes';
import * as editorCommon from 'vs/editor/common/editorCommon';
import {OverviewRulerZone} from 'vs/editor/browser/editorBrowser';
import {ViewPart} from 'vs/editor/browser/view/viewPart';
import {OverviewRulerImpl} from 'vs/editor/browser/viewParts/overviewRuler/overviewRulerImpl';
import {ViewContext} from 'vs/editor/common/view/viewContext';
......@@ -28,8 +27,8 @@ export class DecorationsOverviewRuler extends ViewPart {
private _hideCursor:boolean;
private _cursorPositions: Position[];
private _zonesFromDecorations: OverviewRulerZone[];
private _zonesFromCursors: OverviewRulerZone[];
private _zonesFromDecorations: editorCommon.OverviewRulerZone[];
private _zonesFromCursors: editorCommon.OverviewRulerZone[];
constructor(context:ViewContext, scrollHeight:number, getVerticalOffsetForLine:(lineNumber:number)=>number) {
super(context);
......@@ -138,14 +137,14 @@ export class DecorationsOverviewRuler extends ViewPart {
return this._overviewRuler.getDomNode();
}
private _createZonesFromDecorations(): OverviewRulerZone[] {
private _createZonesFromDecorations(): editorCommon.OverviewRulerZone[] {
let decorations = this._context.model.getAllDecorations();
let zones:OverviewRulerZone[] = [];
let zones:editorCommon.OverviewRulerZone[] = [];
for (let i = 0, len = decorations.length; i < len; i++) {
let dec = decorations[i];
if (dec.options.overviewRuler.color) {
zones.push(new OverviewRulerZone(
zones.push(new editorCommon.OverviewRulerZone(
dec.range.startLineNumber,
dec.range.endLineNumber,
dec.options.overviewRuler.position,
......@@ -159,13 +158,13 @@ export class DecorationsOverviewRuler extends ViewPart {
return zones;
}
private _createZonesFromCursors(): OverviewRulerZone[] {
let zones:OverviewRulerZone[] = [];
private _createZonesFromCursors(): editorCommon.OverviewRulerZone[] {
let zones:editorCommon.OverviewRulerZone[] = [];
for (let i = 0, len = this._cursorPositions.length; i < len; i++) {
let cursor = this._cursorPositions[i];
zones.push(new OverviewRulerZone(
zones.push(new editorCommon.OverviewRulerZone(
cursor.lineNumber,
cursor.lineNumber,
editorCommon.OverviewRulerLane.Full,
......@@ -202,7 +201,7 @@ export class DecorationsOverviewRuler extends ViewPart {
}
}
var allZones:OverviewRulerZone[] = [];
var allZones:editorCommon.OverviewRulerZone[] = [];
allZones = allZones.concat(this._zonesFromCursors);
allZones = allZones.concat(this._zonesFromDecorations);
......@@ -217,11 +216,11 @@ export class DecorationsOverviewRuler extends ViewPart {
ctx2.lineWidth = 1;
ctx2.strokeStyle = 'rgba(197,197,197,0.8)';
ctx2.moveTo(0, 0);
ctx2.lineTo(0, this._overviewRuler.getHeight());
ctx2.lineTo(0, this._overviewRuler.getPixelHeight());
ctx2.stroke();
ctx2.moveTo(0, 0);
ctx2.lineTo(this._overviewRuler.getWidth(), 0);
ctx2.lineTo(this._overviewRuler.getPixelWidth(), 0);
ctx2.stroke();
}
}
......
......@@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import {IConfigurationChangedEvent, OverviewRulerPosition, IScrollEvent} from 'vs/editor/common/editorCommon';
import {IConfigurationChangedEvent, OverviewRulerPosition, OverviewRulerZone, IScrollEvent} from 'vs/editor/common/editorCommon';
import {ViewEventHandler} from 'vs/editor/common/viewModel/viewEventHandler';
import {IOverviewRuler, OverviewRulerZone} from 'vs/editor/browser/editorBrowser';
import {IOverviewRuler} from 'vs/editor/browser/editorBrowser';
import {OverviewRulerImpl} from 'vs/editor/browser/viewParts/overviewRuler/overviewRulerImpl';
import {ViewContext} from 'vs/editor/common/view/viewContext';
......
......@@ -5,269 +5,10 @@
'use strict';
import {StyleMutator} from 'vs/base/browser/styleMutator';
import {OverviewRulerPosition, OverviewRulerLane} from 'vs/editor/common/editorCommon';
import {OverviewRulerZone, ColorZone} from 'vs/editor/browser/editorBrowser';
class ZoneManager {
private _getVerticalOffsetForLine:(lineNumber:number)=>number;
private _zones: OverviewRulerZone[];
private _colorZonesInvalid: boolean;
private _lineHeight: number;
private _width: number;
private _height: number;
private _outerHeight: number;
private _maximumHeight: number;
private _minimumHeight: number;
private _useDarkColor: boolean;
private _lastAssignedId;
private _color2Id: { [color:string]: number; };
private _id2Color: string[];
constructor(getVerticalOffsetForLine:(lineNumber:number)=>number) {
this._getVerticalOffsetForLine = getVerticalOffsetForLine;
this._zones = [];
this._colorZonesInvalid = false;
this._lineHeight = 0;
this._width = 0;
this._height = 0;
this._outerHeight = 0;
this._maximumHeight = 0;
this._minimumHeight = 0;
this._useDarkColor = false;
this._lastAssignedId = 0;
this._color2Id = Object.create(null);
this._id2Color = [];
}
public getId2Color(): string[] {
return this._id2Color;
}
public setZones(newZones: OverviewRulerZone[]): void {
newZones.sort((a, b) => a.compareTo(b));
let oldZones = this._zones;
let oldIndex = 0;
let oldLength = this._zones.length;
let newIndex = 0;
let newLength = newZones.length;
let result: OverviewRulerZone[] = [];
while (newIndex < newLength) {
let newZone = newZones[newIndex];
if (oldIndex >= oldLength) {
result.push(newZone);
newIndex++;
} else {
let oldZone = oldZones[oldIndex];
let cmp = oldZone.compareTo(newZone);
if (cmp < 0) {
oldIndex++;
} else if (cmp > 0) {
result.push(newZone);
newIndex++;
} else {
// cmp === 0
result.push(oldZone);
oldIndex++;
newIndex++;
}
}
}
this._zones = result;
}
public setLineHeight(lineHeight:number): boolean {
if (this._lineHeight === lineHeight) {
return false;
}
this._lineHeight = lineHeight;
this._colorZonesInvalid = true;
return true;
}
public getWidth(): number {
return this._width;
}
public setWidth(width:number): boolean {
if (this._width === width) {
return false;
}
this._width = width;
this._colorZonesInvalid = true;
return true;
}
public getHeight(): number {
return this._height;
}
public setHeight(height:number): boolean {
if (this._height === height) {
return false;
}
this._height = height;
this._colorZonesInvalid = true;
return true;
}
public getOuterHeight(): number {
return this._outerHeight;
}
public setOuterHeight(outerHeight:number): boolean {
if (this._outerHeight === outerHeight) {
return false;
}
this._outerHeight = outerHeight;
this._colorZonesInvalid = true;
return true;
}
public setMaximumHeight(maximumHeight:number): boolean {
if (this._maximumHeight === maximumHeight) {
return false;
}
this._maximumHeight = maximumHeight;
this._colorZonesInvalid = true;
return true;
}
public setMinimumHeight(minimumHeight:number): boolean {
if (this._minimumHeight === minimumHeight) {
return false;
}
this._minimumHeight = minimumHeight;
this._colorZonesInvalid = true;
return true;
}
public setUseDarkColor(useDarkColor:boolean): boolean {
if (this._useDarkColor === useDarkColor) {
return false;
}
this._useDarkColor = useDarkColor;
this._colorZonesInvalid = true;
return true;
}
public resolveColorZones(): ColorZone[] {
const colorZonesInvalid = this._colorZonesInvalid;
const lineHeight = Math.floor(this._lineHeight); // @perf
const totalHeight = Math.floor(this._height); // @perf
const maximumHeight = Math.floor(this._maximumHeight); // @perf
const minimumHeight = Math.floor(this._minimumHeight); // @perf
const useDarkColor = this._useDarkColor; // @perf
const outerHeight = Math.floor(this._outerHeight); // @perf
const heightRatio = totalHeight / outerHeight;
let allColorZones: ColorZone[] = [];
for (let i = 0, len = this._zones.length; i < len; i++) {
let zone = this._zones[i];
if (!colorZonesInvalid) {
let colorZones = zone.getColorZones();
if (colorZones) {
for (let j = 0, lenJ = colorZones.length; j < lenJ; j++) {
allColorZones.push(colorZones[j]);
}
continue;
}
}
let y1 = Math.floor(this._getVerticalOffsetForLine(zone.startLineNumber));
let y2 = Math.floor(this._getVerticalOffsetForLine(zone.endLineNumber)) + lineHeight;
y1 = Math.floor(y1 * heightRatio);
y2 = Math.floor(y2 * heightRatio);
let colorZones: ColorZone[] = [];
if (zone.forceHeight) {
y2 = y1 + zone.forceHeight;
colorZones.push(this.createZone(totalHeight, y1, y2, zone.forceHeight, zone.forceHeight, zone.getColor(useDarkColor), zone.position));
} else {
// Figure out if we can render this in one continuous zone
let zoneLineNumbers = zone.endLineNumber - zone.startLineNumber + 1;
let zoneMaximumHeight = zoneLineNumbers * maximumHeight;
if (y2 - y1 > zoneMaximumHeight) {
// We need to draw one zone per line
for (let lineNumber = zone.startLineNumber; lineNumber <= zone.endLineNumber; lineNumber++) {
y1 = Math.floor(this._getVerticalOffsetForLine(lineNumber));
y2 = y1 + lineHeight;
y1 = Math.floor(y1 * heightRatio);
y2 = Math.floor(y2 * heightRatio);
colorZones.push(this.createZone(totalHeight, y1, y2, minimumHeight, maximumHeight, zone.getColor(useDarkColor), zone.position));
}
} else {
colorZones.push(this.createZone(totalHeight, y1, y2, minimumHeight, zoneMaximumHeight, zone.getColor(useDarkColor), zone.position));
}
}
zone.setColorZones(colorZones);
for (let j = 0, lenJ = colorZones.length; j < lenJ; j++) {
allColorZones.push(colorZones[j]);
}
}
this._colorZonesInvalid = false;
let sortFunc = (a:ColorZone, b:ColorZone) => {
if (a.colorId === b.colorId) {
if (a.from === b.from) {
return a.to - b.to;
}
return a.from - b.from;
}
return a.colorId - b.colorId;
};
allColorZones.sort(sortFunc);
return allColorZones;
}
public createZone(totalHeight:number, y1:number, y2:number, minimumHeight:number, maximumHeight:number, color:string, position:OverviewRulerLane): ColorZone {
totalHeight = Math.floor(totalHeight); // @perf
y1 = Math.floor(y1); // @perf
y2 = Math.floor(y2); // @perf
minimumHeight = Math.floor(minimumHeight); // @perf
maximumHeight = Math.floor(maximumHeight); // @perf
let ycenter = Math.floor((y1 + y2) / 2);
let halfHeight = (y2 - ycenter);
if (halfHeight > maximumHeight / 2) {
halfHeight = maximumHeight / 2;
}
if (halfHeight < minimumHeight / 2) {
halfHeight = minimumHeight / 2;
}
if (ycenter - halfHeight < 0) {
ycenter = halfHeight;
}
if (ycenter + halfHeight > totalHeight) {
ycenter = totalHeight - halfHeight;
}
let colorId = this._color2Id[color];
if (!colorId) {
colorId = (++this._lastAssignedId);
this._color2Id[color] = colorId;
this._id2Color[colorId] = color;
}
return new ColorZone(ycenter - halfHeight, ycenter + halfHeight, colorId, position);
}
}
import {OverviewRulerPosition, OverviewRulerLane, OverviewRulerZone, ColorZone} from 'vs/editor/common/editorCommon';
import {IDisposable} from 'vs/base/common/lifecycle';
import * as browser from 'vs/base/browser/browser';
import {OverviewZoneManager} from 'vs/editor/common/view/overviewZoneManager';
export class OverviewRulerImpl {
......@@ -276,9 +17,11 @@ export class OverviewRulerImpl {
private _canvasLeftOffset: number;
private _domNode: HTMLCanvasElement;
private _lanesCount:number;
private _zoneManager: ZoneManager;
private _zoneManager: OverviewZoneManager;
private _canUseTranslate3d: boolean;
private _zoomListener: IDisposable;
constructor(canvasLeftOffset:number, cssClassName:string, scrollHeight:number, lineHeight:number, canUseTranslate3d:boolean, minimumHeight:number, maximumHeight:number, getVerticalOffsetForLine:(lineNumber:number)=>number) {
this._canvasLeftOffset = canvasLeftOffset;
......@@ -290,17 +33,28 @@ export class OverviewRulerImpl {
this._canUseTranslate3d = canUseTranslate3d;
this._zoneManager = new ZoneManager(getVerticalOffsetForLine);
this._zoneManager = new OverviewZoneManager(getVerticalOffsetForLine);
this._zoneManager.setMinimumHeight(minimumHeight);
this._zoneManager.setMaximumHeight(maximumHeight);
this._zoneManager.setUseDarkColor(false);
this._zoneManager.setWidth(0);
this._zoneManager.setHeight(0);
this._zoneManager.setDOMWidth(0);
this._zoneManager.setDOMHeight(0);
this._zoneManager.setOuterHeight(scrollHeight);
this._zoneManager.setLineHeight(lineHeight);
this._zoomListener = browser.onDidChangeZoomLevel(() => {
this._zoneManager.setPixelRatio(browser.getPixelRatio());
this._domNode.style.width = this._zoneManager.getDOMWidth() + 'px';
this._domNode.style.height = this._zoneManager.getDOMHeight() + 'px';
this._domNode.width = this._zoneManager.getCanvasWidth();
this._domNode.height = this._zoneManager.getCanvasHeight();
this.render(true);
});
this._zoneManager.setPixelRatio(browser.getPixelRatio());
}
public dispose(): void {
this._zoomListener.dispose();
this._zoneManager = null;
}
......@@ -309,12 +63,14 @@ export class OverviewRulerImpl {
StyleMutator.setRight(this._domNode, position.right);
let hasChanged = false;
hasChanged = this._zoneManager.setWidth(position.width) || hasChanged;
hasChanged = this._zoneManager.setHeight(position.height) || hasChanged;
hasChanged = this._zoneManager.setDOMWidth(position.width) || hasChanged;
hasChanged = this._zoneManager.setDOMHeight(position.height) || hasChanged;
if (hasChanged) {
this._domNode.width = this._zoneManager.getWidth();
this._domNode.height = this._zoneManager.getHeight();
this._domNode.style.width = this._zoneManager.getDOMWidth() + 'px';
this._domNode.style.height = this._zoneManager.getDOMHeight() + 'px';
this._domNode.width = this._zoneManager.getCanvasWidth();
this._domNode.height = this._zoneManager.getCanvasHeight();
if (render) {
this.render(true);
......@@ -346,12 +102,12 @@ export class OverviewRulerImpl {
return this._domNode;
}
public getWidth(): number {
return this._zoneManager.getWidth();
public getPixelWidth(): number {
return this._zoneManager.getCanvasWidth();
}
public getHeight(): number {
return this._zoneManager.getHeight();
public getPixelHeight(): number {
return this._zoneManager.getCanvasHeight();
}
public setScrollHeight(scrollHeight:number, render:boolean): void {
......@@ -395,8 +151,8 @@ export class OverviewRulerImpl {
StyleMutator.setTransform(this._domNode, '');
}
const width = this._zoneManager.getWidth();
const height = this._zoneManager.getHeight();
const width = this._zoneManager.getCanvasWidth();
const height = this._zoneManager.getCanvasHeight();
let colorZones = this._zoneManager.resolveColorZones();
let id2Color = this._zoneManager.getId2Color();
......
......@@ -30,7 +30,7 @@ import {Selection} from 'vs/editor/common/core/selection';
interface IEditorDiffDecorations {
decorations:editorCommon.IModelDeltaDecoration[];
overviewZones:editorBrowser.OverviewRulerZone[];
overviewZones:editorCommon.OverviewRulerZone[];
}
interface IEditorDiffDecorationsWithZones extends IEditorDiffDecorations {
......@@ -1476,7 +1476,7 @@ class DiffEdtorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEd
result.decorations.push(createDecoration(lineChange.originalStartLineNumber, 1, lineChange.originalEndLineNumber, Number.MAX_VALUE, 'char-delete', true));
}
result.overviewZones.push(new editorBrowser.OverviewRulerZone(
result.overviewZones.push(new editorCommon.OverviewRulerZone(
lineChange.originalStartLineNumber,
lineChange.originalEndLineNumber,
editorCommon.OverviewRulerLane.Full,
......@@ -1541,7 +1541,7 @@ class DiffEdtorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEd
if (!isChangeOrDelete(lineChange) || !lineChange.charChanges) {
result.decorations.push(createDecoration(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Number.MAX_VALUE, 'char-insert', true));
}
result.overviewZones.push(new editorBrowser.OverviewRulerZone(
result.overviewZones.push(new editorCommon.OverviewRulerZone(
lineChange.modifiedStartLineNumber,
lineChange.modifiedEndLineNumber,
editorCommon.OverviewRulerLane.Full,
......@@ -1656,7 +1656,7 @@ class DiffEdtorWidgetInline extends DiffEditorWidgetStyle implements IDiffEditor
// Add overview zones in the overview ruler
if (isChangeOrDelete(lineChange)) {
result.overviewZones.push(new editorBrowser.OverviewRulerZone(
result.overviewZones.push(new editorCommon.OverviewRulerZone(
lineChange.originalStartLineNumber,
lineChange.originalEndLineNumber,
editorCommon.OverviewRulerLane.Full,
......@@ -1694,7 +1694,7 @@ class DiffEdtorWidgetInline extends DiffEditorWidgetStyle implements IDiffEditor
if (isChangeOrInsert(lineChange)) {
result.decorations.push(createDecoration(lineChange.modifiedStartLineNumber, 1, lineChange.modifiedEndLineNumber, Number.MAX_VALUE, 'line-insert', true));
result.overviewZones.push(new editorBrowser.OverviewRulerZone(
result.overviewZones.push(new editorCommon.OverviewRulerZone(
lineChange.modifiedStartLineNumber,
lineChange.modifiedEndLineNumber,
editorCommon.OverviewRulerLane.Full,
......
......@@ -3600,3 +3600,100 @@ export function cursorStyleToString(cursorStyle:TextEditorCursorStyle): string {
throw new Error('cursorStyleToString: Unknown cursorStyle');
}
}
export class ColorZone {
_colorZoneBrand: void;
from: number;
to: number;
colorId: number;
position: OverviewRulerLane;
constructor(from:number, to:number, colorId:number, position: OverviewRulerLane) {
this.from = from|0;
this.to = to|0;
this.colorId = colorId|0;
this.position = position|0;
}
}
/**
* A zone in the overview ruler
*/
export class OverviewRulerZone {
_overviewRulerZoneBrand: void;
startLineNumber: number;
endLineNumber: number;
position: OverviewRulerLane;
forceHeight: number;
private _color: string;
private _darkColor: string;
private _colorZones: ColorZone[];
constructor(
startLineNumber: number, endLineNumber: number,
position: OverviewRulerLane,
forceHeight: number,
color: string, darkColor: string
) {
this.startLineNumber = startLineNumber;
this.endLineNumber = endLineNumber;
this.position = position;
this.forceHeight = forceHeight;
this._color = color;
this._darkColor = darkColor;
this._colorZones = null;
}
public getColor(useDarkColor:boolean): string {
if (useDarkColor) {
return this._darkColor;
}
return this._color;
}
public equals(other:OverviewRulerZone): boolean {
return (
this.startLineNumber === other.startLineNumber
&& this.endLineNumber === other.endLineNumber
&& this.position === other.position
&& this.forceHeight === other.forceHeight
&& this._color === other._color
&& this._darkColor === other._darkColor
);
}
public compareTo(other:OverviewRulerZone): number {
if (this.startLineNumber === other.startLineNumber) {
if (this.endLineNumber === other.endLineNumber) {
if (this.forceHeight === other.forceHeight) {
if (this.position === other.position) {
if (this._darkColor === other._darkColor) {
if (this._color === other._color) {
return 0;
}
return this._color < other._color ? -1 : 1;
}
return this._darkColor < other._darkColor ? -1 : 1;
}
return this.position - other.position;
}
return this.forceHeight - other.forceHeight;
}
return this.endLineNumber - other.endLineNumber;
}
return this.startLineNumber - other.startLineNumber;
}
public setColorZones(colorZones:ColorZone[]): void {
this._colorZones = colorZones;
}
public getColorZones(): ColorZone[] {
return this._colorZones;
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import {OverviewRulerLane, OverviewRulerZone, ColorZone} from 'vs/editor/common/editorCommon';
export class OverviewZoneManager {
private _getVerticalOffsetForLine:(lineNumber:number)=>number;
private _zones: OverviewRulerZone[];
private _colorZonesInvalid: boolean;
private _lineHeight: number;
private _domWidth: number;
private _domHeight: number;
private _outerHeight: number;
private _maximumHeight: number;
private _minimumHeight: number;
private _useDarkColor: boolean;
private _pixelRatio: number;
private _lastAssignedId;
private _color2Id: { [color:string]: number; };
private _id2Color: string[];
constructor(getVerticalOffsetForLine:(lineNumber:number)=>number) {
this._getVerticalOffsetForLine = getVerticalOffsetForLine;
this._zones = [];
this._colorZonesInvalid = false;
this._lineHeight = 0;
this._domWidth = 0;
this._domHeight = 0;
this._outerHeight = 0;
this._maximumHeight = 0;
this._minimumHeight = 0;
this._useDarkColor = false;
this._pixelRatio = 1;
this._lastAssignedId = 0;
this._color2Id = Object.create(null);
this._id2Color = [];
}
public getId2Color(): string[] {
return this._id2Color;
}
public setZones(newZones: OverviewRulerZone[]): void {
newZones.sort((a, b) => a.compareTo(b));
let oldZones = this._zones;
let oldIndex = 0;
let oldLength = this._zones.length;
let newIndex = 0;
let newLength = newZones.length;
let result: OverviewRulerZone[] = [];
while (newIndex < newLength) {
let newZone = newZones[newIndex];
if (oldIndex >= oldLength) {
result.push(newZone);
newIndex++;
} else {
let oldZone = oldZones[oldIndex];
let cmp = oldZone.compareTo(newZone);
if (cmp < 0) {
oldIndex++;
} else if (cmp > 0) {
result.push(newZone);
newIndex++;
} else {
// cmp === 0
result.push(oldZone);
oldIndex++;
newIndex++;
}
}
}
this._zones = result;
}
public setLineHeight(lineHeight:number): boolean {
if (this._lineHeight === lineHeight) {
return false;
}
this._lineHeight = lineHeight;
this._colorZonesInvalid = true;
return true;
}
public setPixelRatio(pixelRatio:number): void {
this._pixelRatio = pixelRatio;
this._colorZonesInvalid = true;
}
public getDOMWidth(): number {
return this._domWidth;
}
public getCanvasWidth(): number {
return this._domWidth * this._pixelRatio;
}
public setDOMWidth(width:number): boolean {
if (this._domWidth === width) {
return false;
}
this._domWidth = width;
this._colorZonesInvalid = true;
return true;
}
public getDOMHeight(): number {
return this._domHeight;
}
public getCanvasHeight(): number {
return this._domHeight * this._pixelRatio;
}
public setDOMHeight(height:number): boolean {
if (this._domHeight === height) {
return false;
}
this._domHeight = height;
this._colorZonesInvalid = true;
return true;
}
public getOuterHeight(): number {
return this._outerHeight;
}
public setOuterHeight(outerHeight:number): boolean {
if (this._outerHeight === outerHeight) {
return false;
}
this._outerHeight = outerHeight;
this._colorZonesInvalid = true;
return true;
}
public setMaximumHeight(maximumHeight:number): boolean {
if (this._maximumHeight === maximumHeight) {
return false;
}
this._maximumHeight = maximumHeight;
this._colorZonesInvalid = true;
return true;
}
public setMinimumHeight(minimumHeight:number): boolean {
if (this._minimumHeight === minimumHeight) {
return false;
}
this._minimumHeight = minimumHeight;
this._colorZonesInvalid = true;
return true;
}
public setUseDarkColor(useDarkColor:boolean): boolean {
if (this._useDarkColor === useDarkColor) {
return false;
}
this._useDarkColor = useDarkColor;
this._colorZonesInvalid = true;
return true;
}
public resolveColorZones(): ColorZone[] {
const colorZonesInvalid = this._colorZonesInvalid;
const lineHeight = Math.floor(this._lineHeight); // @perf
const totalHeight = Math.floor(this.getCanvasHeight()); // @perf
const maximumHeight = Math.floor(this._maximumHeight * this._pixelRatio); // @perf
const minimumHeight = Math.floor(this._minimumHeight * this._pixelRatio); // @perf
const useDarkColor = this._useDarkColor; // @perf
const outerHeight = Math.floor(this._outerHeight); // @perf
const heightRatio = totalHeight / outerHeight;
let allColorZones: ColorZone[] = [];
for (let i = 0, len = this._zones.length; i < len; i++) {
let zone = this._zones[i];
if (!colorZonesInvalid) {
let colorZones = zone.getColorZones();
if (colorZones) {
for (let j = 0, lenJ = colorZones.length; j < lenJ; j++) {
allColorZones.push(colorZones[j]);
}
continue;
}
}
let colorZones: ColorZone[] = [];
if (zone.forceHeight) {
let forcedHeight = Math.floor(zone.forceHeight * this._pixelRatio);
let y1 = Math.floor(this._getVerticalOffsetForLine(zone.startLineNumber));
y1 = Math.floor(y1 * heightRatio);
let y2 = y1 + forcedHeight;
colorZones.push(this.createZone(totalHeight, y1, y2, forcedHeight, forcedHeight, zone.getColor(useDarkColor), zone.position));
} else {
let y1 = Math.floor(this._getVerticalOffsetForLine(zone.startLineNumber));
let y2 = Math.floor(this._getVerticalOffsetForLine(zone.endLineNumber)) + lineHeight;
y1 = Math.floor(y1 * heightRatio);
y2 = Math.floor(y2 * heightRatio);
// Figure out if we can render this in one continuous zone
let zoneLineNumbers = zone.endLineNumber - zone.startLineNumber + 1;
let zoneMaximumHeight = zoneLineNumbers * maximumHeight;
if (y2 - y1 > zoneMaximumHeight) {
// We need to draw one zone per line
for (let lineNumber = zone.startLineNumber; lineNumber <= zone.endLineNumber; lineNumber++) {
y1 = Math.floor(this._getVerticalOffsetForLine(lineNumber));
y2 = y1 + lineHeight;
y1 = Math.floor(y1 * heightRatio);
y2 = Math.floor(y2 * heightRatio);
colorZones.push(this.createZone(totalHeight, y1, y2, minimumHeight, maximumHeight, zone.getColor(useDarkColor), zone.position));
}
} else {
colorZones.push(this.createZone(totalHeight, y1, y2, minimumHeight, zoneMaximumHeight, zone.getColor(useDarkColor), zone.position));
}
}
zone.setColorZones(colorZones);
for (let j = 0, lenJ = colorZones.length; j < lenJ; j++) {
allColorZones.push(colorZones[j]);
}
}
this._colorZonesInvalid = false;
let sortFunc = (a:ColorZone, b:ColorZone) => {
if (a.colorId === b.colorId) {
if (a.from === b.from) {
return a.to - b.to;
}
return a.from - b.from;
}
return a.colorId - b.colorId;
};
allColorZones.sort(sortFunc);
return allColorZones;
}
public createZone(totalHeight:number, y1:number, y2:number, minimumHeight:number, maximumHeight:number, color:string, position:OverviewRulerLane): ColorZone {
totalHeight = Math.floor(totalHeight); // @perf
y1 = Math.floor(y1); // @perf
y2 = Math.floor(y2); // @perf
minimumHeight = Math.floor(minimumHeight); // @perf
maximumHeight = Math.floor(maximumHeight); // @perf
let ycenter = Math.floor((y1 + y2) / 2);
let halfHeight = (y2 - ycenter);
if (halfHeight > maximumHeight / 2) {
halfHeight = maximumHeight / 2;
}
if (halfHeight < minimumHeight / 2) {
halfHeight = minimumHeight / 2;
}
if (ycenter - halfHeight < 0) {
ycenter = halfHeight;
}
if (ycenter + halfHeight > totalHeight) {
ycenter = totalHeight - halfHeight;
}
let colorId = this._color2Id[color];
if (!colorId) {
colorId = (++this._lastAssignedId);
this._color2Id[color] = colorId;
this._id2Color[colorId] = color;
}
return new ColorZone(ycenter - halfHeight, ycenter + halfHeight, colorId, position);
}
}
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import {OverviewRulerLane, OverviewRulerZone, ColorZone} from 'vs/editor/common/editorCommon';
import {OverviewZoneManager} from 'vs/editor/common/view/overviewZoneManager';
suite('Editor View - OverviewZoneManager', () => {
test('pixel ratio 1, dom height 600', () => {
const LINE_COUNT = 50;
const LINE_HEIGHT = 20;
let manager = new OverviewZoneManager((lineNumber) => LINE_HEIGHT * lineNumber);
manager.setMinimumHeight(6);
manager.setMaximumHeight(6);
manager.setUseDarkColor(false);
manager.setDOMWidth(30);
manager.setDOMHeight(600);
manager.setOuterHeight(LINE_COUNT * LINE_HEIGHT);
manager.setLineHeight(LINE_HEIGHT);
manager.setPixelRatio(1);
manager.setZones([
new OverviewRulerZone(1, 1, OverviewRulerLane.Full, 10, '1', '1'),
new OverviewRulerZone(10, 10, OverviewRulerLane.Full, 0, '2', '2'),
new OverviewRulerZone(30, 31, OverviewRulerLane.Full, 0, '3', '3'),
new OverviewRulerZone(50, 50, OverviewRulerLane.Full, 0, '4', '4'),
]);
// one line = 12, but cap is at 6
assert.deepEqual(manager.resolveColorZones(), [
new ColorZone(12, 22, 1, OverviewRulerLane.Full), // forced height of 10
new ColorZone(123, 129, 2, OverviewRulerLane.Full), // 120 -> 132
new ColorZone(363, 369, 3, OverviewRulerLane.Full), // 360 -> 372 [360 -> 384]
new ColorZone(375, 381, 3, OverviewRulerLane.Full), // 372 -> 384 [360 -> 384]
new ColorZone(594, 600, 4, OverviewRulerLane.Full), // 588 -> 600
]);
});
test('pixel ratio 1, dom height 300', () => {
const LINE_COUNT = 50;
const LINE_HEIGHT = 20;
let manager = new OverviewZoneManager((lineNumber) => LINE_HEIGHT * lineNumber);
manager.setMinimumHeight(6);
manager.setMaximumHeight(6);
manager.setUseDarkColor(false);
manager.setDOMWidth(30);
manager.setDOMHeight(300);
manager.setOuterHeight(LINE_COUNT * LINE_HEIGHT);
manager.setLineHeight(LINE_HEIGHT);
manager.setPixelRatio(1);
manager.setZones([
new OverviewRulerZone(1, 1, OverviewRulerLane.Full, 10, '1', '1'),
new OverviewRulerZone(10, 10, OverviewRulerLane.Full, 0, '2', '2'),
new OverviewRulerZone(30, 31, OverviewRulerLane.Full, 0, '3', '3'),
new OverviewRulerZone(50, 50, OverviewRulerLane.Full, 0, '4', '4'),
]);
// one line = 6, cap is at 6
assert.deepEqual(manager.resolveColorZones(), [
new ColorZone(6, 16, 1, OverviewRulerLane.Full), // forced height of 10
new ColorZone(60, 66, 2, OverviewRulerLane.Full), // 60 -> 66
new ColorZone(180, 192, 3, OverviewRulerLane.Full), // 180 -> 192
new ColorZone(294, 300, 4, OverviewRulerLane.Full), // 294 -> 300
]);
});
test('pixel ratio 2, dom height 300', () => {
const LINE_COUNT = 50;
const LINE_HEIGHT = 20;
let manager = new OverviewZoneManager((lineNumber) => LINE_HEIGHT * lineNumber);
manager.setMinimumHeight(6);
manager.setMaximumHeight(6);
manager.setUseDarkColor(false);
manager.setDOMWidth(30);
manager.setDOMHeight(300);
manager.setOuterHeight(LINE_COUNT * LINE_HEIGHT);
manager.setLineHeight(LINE_HEIGHT);
manager.setPixelRatio(2);
manager.setZones([
new OverviewRulerZone(1, 1, OverviewRulerLane.Full, 10, '1', '1'),
new OverviewRulerZone(10, 10, OverviewRulerLane.Full, 0, '2', '2'),
new OverviewRulerZone(30, 31, OverviewRulerLane.Full, 0, '3', '3'),
new OverviewRulerZone(50, 50, OverviewRulerLane.Full, 0, '4', '4'),
]);
// one line = 6, cap is at 12
assert.deepEqual(manager.resolveColorZones(), [
new ColorZone(12, 32, 1, OverviewRulerLane.Full), // forced height of 10 => forced height of 20
new ColorZone(120, 132, 2, OverviewRulerLane.Full), // 120 -> 132
new ColorZone(360, 384, 3, OverviewRulerLane.Full), // 360 -> 384
new ColorZone(588, 600, 4, OverviewRulerLane.Full), // 588 -> 600
]);
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册