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(env): support iframe with relative window/document #8897

Merged
merged 14 commits into from
May 8, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [next]

- feat(env): relative window/document, support iframe [#8897](https://github.com/fabricjs/fabric.js/pull/8897)
- docs(): add repo repro link to `bug_report.yml` [#8900](https://github.com/fabricjs/fabric.js/pull/8900)
- refactor(fabric.Line): Line position is calculated from the center between the 2 points now [#8877](https://github.com/fabricjs/fabric.js/pull/8877)
- chore(Path, Polyline): Clean up old SVG import code [#8857](https://github.com/fabricjs/fabric.js/pull/8857)
Expand Down
2 changes: 1 addition & 1 deletion fabric.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export { getEnv, getDocument, getWindow, setEnv } from './src/env';
export { getEnv, getFabricDocument, getFabricWindow, setEnv } from './src/env';
export { cache } from './src/cache';
export { VERSION as version, iMatrix } from './src/constants';
export { config } from './src/config';
Expand Down
41 changes: 21 additions & 20 deletions src/canvas/Canvas.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { LEFT_CLICK, MIDDLE_CLICK, RIGHT_CLICK } from '../constants';
import { getDocument, getWindow } from '../env';
import {
CanvasEvents,
DragEventData,
Expand All @@ -15,6 +14,7 @@ import type { IText } from '../shapes/IText/IText';
import type { FabricObject } from '../shapes/Object/FabricObject';
import { AssertKeys } from '../typedefs';
import { isTouchEvent, stopEvent } from '../util/dom_event';
import { getDocumentFromElement, getWindowFromElement } from '../util/dom_misc';
import { sendPointToPlane } from '../util/misc/planeChange';
import {
isFabricObjectWithDragSupport,
Expand Down Expand Up @@ -165,7 +165,7 @@ export class Canvas extends SelectableCanvas {
addOrRemove(functor: any, eventjsFunctor: 'add' | 'remove') {
const canvasElement = this.upperCanvasEl,
eventTypePrefix = this._getEventPrefix();
functor(getWindow(), 'resize', this._onResize);
functor(getWindowFromElement(canvasElement), 'resize', this._onResize);
functor(canvasElement, eventTypePrefix + 'down', this._onMouseDown);
functor(
canvasElement,
Expand Down Expand Up @@ -207,25 +207,26 @@ export class Canvas extends SelectableCanvas {
this.addOrRemove(removeListener, 'remove');
// if you dispose on a mouseDown, before mouse up, you need to clean document to...
const eventTypePrefix = this._getEventPrefix();
const doc = getDocumentFromElement(this.upperCanvasEl);
removeListener(
getDocument(),
doc,
`${eventTypePrefix}up`,
this._onMouseUp as EventListener
);
removeListener(
getDocument(),
doc,
'touchend',
this._onTouchEnd as EventListener,
addEventOptions
);
removeListener(
getDocument(),
doc,
`${eventTypePrefix}move`,
this._onMouseMove as EventListener,
addEventOptions
);
removeListener(
getDocument(),
doc,
'touchmove',
this._onMouseMove as EventListener,
addEventOptions
Expand Down Expand Up @@ -614,22 +615,23 @@ export class Canvas extends SelectableCanvas {
this._resetTransformEventData();
const canvasElement = this.upperCanvasEl,
eventTypePrefix = this._getEventPrefix();
const doc = getDocumentFromElement(canvasElement);
addListener(
getDocument(),
doc,
'touchend',
this._onTouchEnd as EventListener,
addEventOptions
);
addListener(
getDocument(),
doc,
'touchmove',
this._onMouseMove as EventListener,
addEventOptions
);
// Unbind mousedown to prevent double triggers from touch devices
removeListener(
canvasElement,
eventTypePrefix + 'down',
`${eventTypePrefix}down`,
this._onMouseDown as EventListener
);
}
Expand All @@ -649,13 +651,10 @@ export class Canvas extends SelectableCanvas {
this._onMouseMove as EventListener,
addEventOptions
);
const doc = getDocumentFromElement(canvasElement);
addListener(doc, `${eventTypePrefix}up`, this._onMouseUp as EventListener);
addListener(
getDocument(),
`${eventTypePrefix}up`,
this._onMouseUp as EventListener
);
addListener(
getDocument(),
doc,
`${eventTypePrefix}move`,
this._onMouseMove as EventListener,
addEventOptions
Expand All @@ -675,14 +674,15 @@ export class Canvas extends SelectableCanvas {
this._resetTransformEventData();
this.mainTouchId = null;
const eventTypePrefix = this._getEventPrefix();
const doc = getDocumentFromElement(this.upperCanvasEl);
removeListener(
getDocument(),
doc,
'touchend',
this._onTouchEnd as EventListener,
addEventOptions
);
removeListener(
getDocument(),
doc,
'touchmove',
this._onMouseMove as EventListener,
addEventOptions
Expand All @@ -695,7 +695,7 @@ export class Canvas extends SelectableCanvas {
// from touch devices
addListener(
this.upperCanvasEl,
eventTypePrefix + 'down',
`${eventTypePrefix}down`,
this._onMouseDown as EventListener
);
this._willAddMouseDown = 0;
Expand All @@ -712,13 +712,14 @@ export class Canvas extends SelectableCanvas {
const canvasElement = this.upperCanvasEl,
eventTypePrefix = this._getEventPrefix();
if (this._isMainEvent(e)) {
const doc = getDocumentFromElement(this.upperCanvasEl);
removeListener(
getDocument(),
doc,
`${eventTypePrefix}up`,
this._onMouseUp as EventListener
);
removeListener(
getDocument(),
doc,
`${eventTypePrefix}move`,
this._onMouseMove as EventListener,
addEventOptions
Expand Down
9 changes: 5 additions & 4 deletions src/canvas/SelectableCanvas.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getDocument, getEnv } from '../env';
import { getFabricDocument, getEnv } from '../env';
import { dragHandler } from '../controls/drag';
import { getActionFromCorner } from '../controls/util';
import { Point } from '../Point';
Expand Down Expand Up @@ -31,6 +31,7 @@ import { TSVGReviver } from '../typedefs';
import { sendPointToPlane } from '../util/misc/planeChange';
import { ActiveSelection } from '../shapes/ActiveSelection';
import type { TDestroyedCanvas } from './StaticCanvas';
import { createCanvasElement } from '../util';

export const DefaultCanvasProperties = {
uniformScaling: true,
Expand Down Expand Up @@ -1192,7 +1193,7 @@ export class SelectableCanvas<

// if there is no upperCanvas (most common case) we create one.
if (!this.upperCanvasEl) {
this.upperCanvasEl = this._createCanvasElement();
this.upperCanvasEl = createCanvasElement();
}
const upperCanvasEl = this.upperCanvasEl;
// we assign the same classname of the lowerCanvas
Expand All @@ -1210,15 +1211,15 @@ export class SelectableCanvas<
}

protected _createCacheCanvas() {
this.pixelFindCanvasEl = this._createCanvasElement();
this.pixelFindCanvasEl = createCanvasElement();
this.pixelFindContext = this.pixelFindCanvasEl.getContext('2d', {
willReadFrequently: true,
})!;
this.setTargetFindTolerance(this.targetFindTolerance);
}

protected _initWrapperElement() {
const container = getDocument().createElement('div');
const container = getFabricDocument().createElement('div');
container.classList.add(this.containerClass);
this.wrapperEl = wrapElement(this.lowerCanvasEl, container);
this.wrapperEl.setAttribute('data-fabric', 'wrapper');
Expand Down
22 changes: 3 additions & 19 deletions src/canvas/StaticCanvas.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getDocument, getEnv } from '../env';
import { getFabricDocument, getEnv } from '../env';
import { config } from '../config';
import { iMatrix, VERSION } from '../constants';
import type { CanvasEvents, StaticCanvasEvents } from '../EventTypeDefs';
Expand Down Expand Up @@ -56,8 +56,6 @@ export type TDestroyedCanvas<T extends StaticCanvas> = TDestroyed<
| '_activeSelection'
>;

const CANVAS_INIT_ERROR = 'Could not initialize `canvas` element';

export type TCanvasSizeOptions = {
backstoreOnly?: boolean;
cssOnly?: boolean;
Expand Down Expand Up @@ -417,20 +415,6 @@ export class StaticCanvas<
return (this._offset = getElementOffset(this.lowerCanvasEl));
}

/**
* @private
*/
protected _createCanvasElement() {
const element = createCanvasElement();
if (!element) {
throw new Error(CANVAS_INIT_ERROR);
}
if (typeof element.getContext === 'undefined') {
throw new Error(CANVAS_INIT_ERROR);
}
return element;
}
ShaMan123 marked this conversation as resolved.
Show resolved Hide resolved

/**
* Creates a bottom canvas
* @private
Expand All @@ -442,8 +426,8 @@ export class StaticCanvas<
this.lowerCanvasEl = canvasEl;
} else {
this.lowerCanvasEl =
(getDocument().getElementById(canvasEl) as HTMLCanvasElement) ||
this._createCanvasElement();
(getFabricDocument().getElementById(canvasEl) as HTMLCanvasElement) ||
createCanvasElement();
}
if (this.lowerCanvasEl.hasAttribute('data-fabric')) {
/* _DEV_MODE_START_ */
Expand Down
4 changes: 2 additions & 2 deletions src/env/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export const setEnv = (value: TFabricEnv) => {

export const getEnv = () => env || getBrowserEnv();

export const getDocument = (): Document => getEnv().document;
export const getFabricDocument = (): Document => getEnv().document;

export const getWindow = (): (Window & typeof globalThis) | DOMWindow =>
export const getFabricWindow = (): (Window & typeof globalThis) | DOMWindow =>
getEnv().window;
10 changes: 5 additions & 5 deletions src/filters/WebGLFilterBackend.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getWindow } from '../env';
import { getFabricWindow } from '../env';
import { config } from '../config';
import { createCanvasElement } from '../util/misc/dom';
import {
Expand Down Expand Up @@ -97,13 +97,13 @@ export class WebGLFilterBackend {
targetCanvas.width = width;
targetCanvas.height = height;

startTime = getWindow().performance.now();
startTime = getFabricWindow().performance.now();
this.copyGLTo2D.call(testContext, this.gl, testPipelineState);
const drawImageTime = getWindow().performance.now() - startTime;
const drawImageTime = getFabricWindow().performance.now() - startTime;

startTime = getWindow().performance.now();
startTime = getFabricWindow().performance.now();
copyGLTo2DPutImageData.call(testContext, this.gl, testPipelineState);
const putImageDataTime = getWindow().performance.now() - startTime;
const putImageDataTime = getFabricWindow().performance.now() - startTime;

if (drawImageTime > putImageDataTime) {
this.imageBuffer = imageBuffer;
Expand Down
4 changes: 2 additions & 2 deletions src/parser/loadSVGFromString.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { getWindow } from '../env';
import { getFabricWindow } from '../env';
import { LoadImageOptions } from '../util/misc/objectEnlive';
import { parseSVGDocument } from './parseSVGDocument';
import type { SVGParsingOutput, TSvgReviverCallback } from './typedefs';
Expand All @@ -22,7 +22,7 @@ export function loadSVGFromString(
reviver?: TSvgReviverCallback,
options?: LoadImageOptions
): Promise<SVGParsingOutput> {
const parser = new (getWindow().DOMParser)(),
const parser = new (getFabricWindow().DOMParser)(),
// should we use `image/svg+xml` here?
doc = parser.parseFromString(string.trim(), 'text/xml');
return parseSVGDocument(doc.documentElement, reviver, options);
Expand Down
6 changes: 4 additions & 2 deletions src/shapes/IText/DraggableTextDelegate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type { Canvas } from '../../canvas/Canvas';
import { getDocument } from '../../env';
import {
DragEventData,
DropEventData,
Expand All @@ -10,6 +9,7 @@ import type { IText } from './IText';
import { setStyle } from '../../util/dom_style';
import { cloneDeep } from '../../util/internals/cloneDeep';
import { TextStyleDeclaration } from '../Text/StyledText';
import { getDocumentFromElement } from '../../util/dom_misc';

/**
* #### Dragging IText/Textbox Lifecycle
Expand Down Expand Up @@ -159,7 +159,9 @@ export class DraggableTextDelegate {
this.__dragImageDisposer = () => {
dragImage.remove();
};
getDocument().body.appendChild(dragImage);
getDocumentFromElement(
(e.target || this.target.hiddenTextarea)! as HTMLElement
).body.appendChild(dragImage);
e.dataTransfer?.setDragImage(dragImage, offset.x, offset.y);
}

Expand Down
6 changes: 3 additions & 3 deletions src/shapes/IText/ITextBehavior.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { getDocument } from '../../env';
import {
ObjectEvents,
TPointerEvent,
Expand All @@ -13,6 +12,7 @@ import type { ValueAnimation } from '../../util/animation/ValueAnimation';
import type { TextStyleDeclaration } from '../Text/StyledText';
import type { SerializedTextProps, TextProps } from '../Text/Text';
import { TProps } from '../Object/types';
import { getDocumentFromElement } from '../../util/dom_misc';

/**
* extend this regex to support non english languages
Expand Down Expand Up @@ -403,9 +403,9 @@ export abstract class ITextBehavior<
* called by {@link canvas#textEditingManager}
*/
updateSelectionOnMouseMove(e: TPointerEvent) {
const el = this.hiddenTextarea!;
// regain focus
getDocument().activeElement !== this.hiddenTextarea &&
this.hiddenTextarea!.focus();
getDocumentFromElement(el).activeElement !== el && el.focus();

const newSelectionStart = this.getSelectionStartFromPointer(e),
currentStart = this.selectionStart,
Expand Down
10 changes: 7 additions & 3 deletions src/shapes/IText/ITextKeyBehavior.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
//@ts-nocheck

import { config } from '../../config';
import { getDocument, getEnv } from '../../env';
import { getFabricDocument, getEnv } from '../../env';
import { TPointerEvent } from '../../EventTypeDefs';
import { capValue } from '../../util/misc/capValue';
import { ITextBehavior, ITextEvents } from './ITextBehavior';
import type { TKeyMapIText } from './constants';
import { TProps } from '../Object/types';
import { TextProps, SerializedTextProps } from '../Text/Text';
import { getDocumentFromElement } from '../../util/dom_misc';

export abstract class ITextKeyBehavior<
Props extends TProps<TextProps> = Partial<TextProps>,
Expand Down Expand Up @@ -59,7 +60,10 @@ export abstract class ITextKeyBehavior<
* Initializes hidden textarea (needed to bring up keyboard in iOS)
*/
initHiddenTextarea() {
this.hiddenTextarea = getDocument().createElement('textarea');
const doc =
(this.canvas && getDocumentFromElement(this.canvas.getElement())) ||
getFabricDocument();
this.hiddenTextarea = doc.createElement('textarea');
this.hiddenTextarea.setAttribute('autocapitalize', 'off');
this.hiddenTextarea.setAttribute('autocorrect', 'off');
this.hiddenTextarea.setAttribute('autocomplete', 'off');
Expand All @@ -74,7 +78,7 @@ export abstract class ITextKeyBehavior<
if (this.hiddenTextareaContainer) {
this.hiddenTextareaContainer.appendChild(this.hiddenTextarea);
} else {
getDocument().body.appendChild(this.hiddenTextarea);
doc.body.appendChild(this.hiddenTextarea);
}

this.hiddenTextarea.addEventListener('blur', this.blur.bind(this));
Expand Down
7 changes: 5 additions & 2 deletions src/shapes/Image.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-nocheck
import { getDocument, getEnv } from '../env';
import { getFabricDocument, getEnv } from '../env';
import type { BaseFilter } from '../filters/BaseFilter';
import { getFilterBackend } from '../filters/FilterBackend';
import { SHARED_ATTRIBUTES } from '../parser/attributes';
Expand Down Expand Up @@ -194,7 +194,10 @@ export class Image<
this.cacheKey = `texture${uid()}`;
this.setElement(
typeof arg0 === 'string'
? (getDocument().getElementById(arg0) as ImageSource)
? ((
(this.canvas && getElementDocument(this.canvas.getElement())) ||
getFabricDocument()
).getElementById(arg0) as ImageSource)
: arg0,
options
);
Expand Down
Loading