Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(engine-render): add render unit system #2025

Merged
merged 3 commits into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/core/src/services/instance/instance.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export interface IUniverInstanceService {
/** @deprecated */
changeDoc(unitId: string, doc: DocumentDataModel): void;

getUnit<T extends UnitModel>(id: string, type: UnitType): Nullable<T>;
getUnit<T extends UnitModel>(id: string, type?: UnitType): Nullable<T>;
getAllUnitsForType<T>(type: UnitType): T[];
getUnitType(unitId: string): UnitType;

Expand Down
6 changes: 6 additions & 0 deletions packages/core/src/shared/lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,12 @@ export class Disposable implements IDisposable {
return this._collection.add(d);
}

protected ensureNotDisposed(): void {
if (this._disposed) {
throw new Error('[Disposable]: object is disposed!');
}
}

dispose(): void {
if (this._disposed) {
return;
Expand Down
4 changes: 2 additions & 2 deletions packages/docs-ui/src/views/doc-canvas-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { IConfigService,
UniverInstanceType,
} from '@univerjs/core';
import { DOCS_COMPONENT_DEFAULT_Z_INDEX, DOCS_COMPONENT_HEADER_LAYER_INDEX, DOCS_COMPONENT_MAIN_LAYER_INDEX, DOCS_VIEW_KEY, VIEWPORT_KEY } from '@univerjs/docs';
import type { IRender, IWheelEvent, RenderManagerService, Scene } from '@univerjs/engine-render';
import type { IRender, IWheelEvent, Scene } from '@univerjs/engine-render';
import { Documents, EVENT_TYPE, IRenderManagerService, Layer, ScrollBar, Viewport } from '@univerjs/engine-render';
import { IEditorService } from '@univerjs/ui';
import { BehaviorSubject, takeUntil } from 'rxjs';
Expand All @@ -39,7 +39,7 @@ export class DocCanvasView extends RxDisposable {
readonly fps$ = this._fps$.asObservable();

constructor(
@IRenderManagerService private readonly _renderManagerService: RenderManagerService,
@IRenderManagerService private readonly _renderManagerService: IRenderManagerService,
@IConfigService private readonly _configService: IConfigService,
@IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService,
@IEditorService private readonly _editorService: IEditorService
Expand Down
3 changes: 2 additions & 1 deletion packages/engine-render/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export * from './engine';
export * from './group';
export * from './layer';
export { IRenderingEngine, UniverRenderEnginePlugin } from './render-engine';
export * from './render-manager.service';
export { type RenderComponentType, IRenderManagerService, RenderManagerService } from './render-manager/render-manager.service';
export { RenderUnit, type IRender, type IRenderControllerCtor, type IRenderController, type IRenderContext } from './render-manager/render-unit';
export * from './scene';
export * from './scene-viewer';
export * from './scroll-timer';
Expand Down
2 changes: 1 addition & 1 deletion packages/engine-render/src/render-engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { Plugin, UniverInstanceType } from '@univerjs/core';
import { createIdentifier, Inject, Injector } from '@wendellhu/redi';

import { Engine } from './engine';
import { IRenderManagerService, RenderManagerService } from './render-manager.service';
import { IRenderManagerService, RenderManagerService } from './render-manager/render-manager.service';

/**
* The global rendering engine.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,30 @@
* limitations under the License.
*/

import type { Nullable } from '@univerjs/core';
import { createIdentifier } from '@wendellhu/redi';
import type { Nullable, UnitModel, UnitType } from '@univerjs/core';
import { Disposable, IUniverInstanceService, toDisposable } from '@univerjs/core';
import type { IDisposable } from '@wendellhu/redi';
import { createIdentifier, Inject, Injector } from '@wendellhu/redi';
import type { Observable } from 'rxjs';
import { BehaviorSubject } from 'rxjs';

import type { BaseObject } from './base-object';
import type { DocComponent } from './components/docs/doc-component';
import type { SheetComponent } from './components/sheets/sheet-component';
import type { Slide } from './components/slides/slide';
import { Engine } from './engine';
import { Scene } from './scene';
import { SceneViewer } from './scene-viewer';
import type { BaseObject } from '../base-object';
import type { DocComponent } from '../components/docs/doc-component';
import type { SheetComponent } from '../components/sheets/sheet-component';
import type { Slide } from '../components/slides/slide';
import { Engine } from '../engine';
import { Scene } from '../scene';
import { SceneViewer } from '../scene-viewer';
import { type IRender, type IRenderControllerCtor, RenderUnit } from './render-unit';

export interface IRenderManagerService {
export type RenderComponentType = SheetComponent | DocComponent | Slide | BaseObject;

export interface IRenderManagerService extends IDisposable {
currentRender$: Observable<Nullable<string>>;
createRender$: Observable<Nullable<string>>;
dispose(): void;
// createRenderWithNewEngine(unitId: string): IRenderManagerService;
createRenderWithParent(unitId: string, parentUnitId: string): IRender;
createRender(unitId: string): IRender;
addItem(unitId: string, item: IRender): void;
addRenderItem(unitId: string, item: IRender): void;
removeRender(unitId: string): void;
setCurrent(unitId: string): void;
getRenderById(unitId: string): Nullable<IRender>;
Expand All @@ -44,24 +47,16 @@ export interface IRenderManagerService {
getCurrent(): Nullable<IRender>;
getFirst(): Nullable<IRender>;
has(unitId: string): boolean;
}

export type RenderComponentType = SheetComponent | DocComponent | Slide | BaseObject;

export interface IRender {
unitId: string;
engine: Engine;
scene: Scene;
mainComponent: Nullable<RenderComponentType>;
components: Map<string, RenderComponentType>;
isMainScene: boolean;
registerRenderControllers<T extends UnitModel>(type: UnitType, ctor: IRenderControllerCtor<T>): IDisposable;
}

const DEFAULT_SCENE_SIZE = { width: 1500, height: 1000 };

const SCENE_NAMESPACE = '_UNIVER_SCENE_';

export class RenderManagerService implements IRenderManagerService {

export class RenderManagerService extends Disposable implements IRenderManagerService {
private _defaultEngine!: Engine;

private _currentUnitId: string = '';
Expand All @@ -81,31 +76,62 @@ export class RenderManagerService implements IRenderManagerService {
return this._defaultEngine;
}

dispose() {
private readonly _renderControllers = new Map<UnitType, Set<IRenderControllerCtor>>();

constructor(
@Inject(Injector) private readonly _injector: Injector,
@IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService
) {
super();
}

override dispose() {
super.dispose();

this._renderMap.forEach((item) => {
this._disposeItem(item);
});

this._renderControllers.clear();
this._renderMap.clear();

this._currentRender$.complete();
}

registerRenderControllers(type: UnitType, ctor: IRenderControllerCtor): IDisposable {
if (!this._renderControllers.has(type)) {
this._renderControllers.set(type, new Set());
}

const set = this._renderControllers.get(type)!;
set.add(ctor);

for (const [renderUnitId, render] of this._renderMap) {
const renderType = this._univerInstanceService.getUnitType(renderUnitId);
if (renderType === type) {
(render as RenderUnit).addRenderControllers([ctor]);
}
}

return toDisposable(() => set.delete(ctor));
}

private _getRenderControllersForType(type: UnitType): Array<IRenderControllerCtor> {
return Array.from(this._renderControllers.get(type) ?? []);
}

createRenderWithParent(unitId: string, parentUnitId: string): IRender {
const parent = this.getRenderById(parentUnitId);
if (parent == null) {
throw new Error('parent render is null');
}
const { scene, engine } = parent;

const { scene, engine } = parent;
const current = this._createRender(unitId, engine, false);

const currentScene = current.scene;

const sv = new SceneViewer(unitId);

sv.addSubScene(currentScene);

scene.addObject(sv);

return current;
Expand Down Expand Up @@ -145,21 +171,22 @@ export class RenderManagerService implements IRenderManagerService {
height,
});

const item: IRender = {
unitId,
const unit = this._univerInstanceService.getUnit(unitId)!;
const type = this._univerInstanceService.getUnitType(unitId);
const ctors = this._getRenderControllersForType(type);
const renderUnit = new RenderUnit(this._injector, {
unit,
engine,
scene,
mainComponent: null,
components: new Map(),
isMainScene,
};

this.addItem(unitId, item);
});
renderUnit.addRenderControllers(ctors);

return item;
this.addRenderItem(unitId, renderUnit);
return renderUnit;
}

addItem(unitId: string, item: IRender) {
addRenderItem(unitId: string, item: IRender) {
this._renderMap.set(unitId, item);
}

Expand Down Expand Up @@ -214,4 +241,4 @@ export class RenderManagerService implements IRenderManagerService {
}
}

export const IRenderManagerService = createIdentifier<RenderManagerService>('univer.render-manager-service');
export const IRenderManagerService = createIdentifier<RenderManagerService>('engine-render.render-manager.service');
102 changes: 102 additions & 0 deletions packages/engine-render/src/render-manager/render-unit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* Copyright 2023-present DreamNum Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import type { Nullable, UnitModel, UnitType } from '@univerjs/core';
import { Disposable } from '@univerjs/core';
import type { IDisposable, Injector } from '@wendellhu/redi';
import type { Engine } from '../engine';
import type { Scene } from '../scene';
import type { RenderComponentType } from './render-manager.service';

export interface IRender {
unitId: string;
engine: Engine;
scene: Scene;
mainComponent: Nullable<RenderComponentType>;
components: Map<string, RenderComponentType>;
isMainScene: boolean;
}

// eslint-disable-next-line ts/no-explicit-any
export interface IRenderControllerCtor<T extends UnitModel = UnitModel> { new(unit: IRenderContext<T>, ...args: any[]): IRenderController }
export interface IRenderController extends IDisposable {}

/**
* This object encapsulates methods or properties to render each element.
*/
export interface IRenderContext<T extends UnitModel = UnitModel> extends IRender {
unit: T;
type: UnitType;
}

/**
* This class is responsible
*/
export class RenderUnit extends Disposable implements IRender {
readonly isRenderUnit: true;

readonly unitId: string;
readonly type: UnitType;

private readonly _injector: Injector;
private readonly _renderControllers: IRenderController[] = [];

private _renderContext: IRenderContext<UnitModel>;
set isMainScene(is: boolean) { this._renderContext.isMainScene = is; }
get isMainScene(): boolean { return this._renderContext.isMainScene; }
set engine(engine: Engine) { this._renderContext.engine = engine; }
get engine(): Engine { return this._renderContext.engine; }
set mainComponent(component: Nullable<RenderComponentType>) { this._renderContext.mainComponent = component; }
get mainComponent(): Nullable<RenderComponentType> { return this._renderContext.mainComponent; }
set scene(scene: Scene) { this._renderContext.scene = scene; }
get scene(): Scene { return this._renderContext.scene; }
get components() { return this._renderContext.components; }

constructor(
parentInjector: Injector,
init: Pick<IRenderContext, 'engine' | 'scene' | 'isMainScene' | 'unit' >
) {
super();

this._injector = parentInjector.createChild();

this._renderContext = {
unit: init.unit,
unitId: this.unitId,
type: init.unit.type,
components: new Map(),
mainComponent: null,
isMainScene: init.isMainScene,
engine: init.engine,
scene: init.scene,
};
}

override dispose() {
this._renderControllers.forEach((controller) => controller.dispose());
this._renderControllers.length = 0;
}

addRenderControllers(ctors: IRenderControllerCtor[]) {
this._initControllers(ctors);
}

private _initControllers(ctors: IRenderControllerCtor[]): void {
ctors
.map((ctor) => this._injector.createInstance(ctor, this._renderContext))
.forEach((controller) => this._renderControllers.push(controller));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ describe('Test format painter rules in controller', () => {
let commandService: ICommandService;
let themeService: ThemeService;
let formatPainterController: FormatPainterController;

beforeEach(() => {
const testBed = createCommandTestBed(TEST_WORKBOOK_DATA, [
[IMarkSelectionService, { useClass: MarkSelectionService }],
Expand Down
Loading
Loading