Skip to content

Commit

Permalink
Merge pull request #1256 from openkraken/feat/window-innerWidth
Browse files Browse the repository at this point in the history
Feat/window inner width
  • Loading branch information
answershuto authored Apr 1, 2022
2 parents 4b5862f + b87882a commit 100f9e1
Show file tree
Hide file tree
Showing 14 changed files with 170 additions and 58 deletions.
22 changes: 22 additions & 0 deletions bridge/bindings/qjs/bom/screen.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,26 @@ IMPL_PROPERTY_GETTER(Screen, height)(JSContext* ctx, JSValue this_val, int argc,
return JS_NewFloat64(ctx, screen->height);
}

// https://drafts.csswg.org/cssom-view/#dom-screen-availwidth
IMPL_PROPERTY_GETTER(Screen, availWidth)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
if (getDartMethod()->getScreen == nullptr) {
return JS_ThrowTypeError(ctx, "Failed to read screen: dart method (getScreen) is not registered.");
}

auto context = static_cast<ExecutionContext*>(JS_GetContextOpaque(ctx));
NativeScreen* screen = getDartMethod()->getScreen(context->getContextId());
return JS_NewFloat64(ctx, screen->width);
}

// https://drafts.csswg.org/cssom-view/#dom-screen-availheight
IMPL_PROPERTY_GETTER(Screen, availHeight)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
if (getDartMethod()->getScreen == nullptr) {
return JS_ThrowTypeError(ctx, "Failed to read screen: dart method (getScreen) is not registered.");
}

auto context = static_cast<ExecutionContext*>(JS_GetContextOpaque(ctx));
NativeScreen* screen = getDartMethod()->getScreen(context->getContextId());
return JS_NewFloat64(ctx, screen->height);
}

} // namespace kraken::binding::qjs
2 changes: 2 additions & 0 deletions bridge/bindings/qjs/bom/screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ class Screen : public HostObject {
private:
DEFINE_READONLY_PROPERTY(width);
DEFINE_READONLY_PROPERTY(height);
DEFINE_READONLY_PROPERTY(availWidth);
DEFINE_READONLY_PROPERTY(availHeight);
};

void bindScreen(ExecutionContext* context);
Expand Down
26 changes: 13 additions & 13 deletions bridge/bindings/qjs/bom/window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -168,23 +168,23 @@ JSValue Window::cancelAnimationFrame(JSContext* ctx, JSValue this_val, int argc,
}

IMPL_PROPERTY_GETTER(Window, devicePixelRatio)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
if (getDartMethod()->devicePixelRatio == nullptr) {
return JS_ThrowTypeError(ctx, "Failed to read devicePixelRatio: dart method (devicePixelRatio) is not register.");
}
auto* context = static_cast<ExecutionContext*>(JS_GetContextOpaque(ctx));

double devicePixelRatio = getDartMethod()->devicePixelRatio(context->getContextId());
return JS_NewFloat64(ctx, devicePixelRatio);
auto* window = static_cast<WindowInstance*>(JS_GetOpaque(this_val, 1));
return window->getBindingProperty("devicePixelRatio");
}

IMPL_PROPERTY_GETTER(Window, colorScheme)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
if (getDartMethod()->platformBrightness == nullptr) {
return JS_ThrowTypeError(ctx, "Failed to read colorScheme: dart method (platformBrightness) not register.");
}
auto* context = static_cast<ExecutionContext*>(JS_GetContextOpaque(ctx));
auto* window = static_cast<WindowInstance*>(JS_GetOpaque(this_val, 1));
return window->getBindingProperty("colorScheme");
}

IMPL_PROPERTY_GETTER(Window, innerWidth)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
auto* window = static_cast<WindowInstance*>(JS_GetOpaque(this_val, 1));
return window->getBindingProperty("innerWidth");
}

const NativeString* code = getDartMethod()->platformBrightness(context->getContextId());
return JS_NewUnicodeString(context->runtime(), ctx, code->string, code->length);
IMPL_PROPERTY_GETTER(Window, innerHeight)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
auto* window = static_cast<WindowInstance*>(JS_GetOpaque(this_val, 1));
return window->getBindingProperty("innerHeight");
}

IMPL_PROPERTY_GETTER(Window, __location__)(JSContext* ctx, JSValue this_val, int argc, JSValue* argv) {
Expand Down
2 changes: 2 additions & 0 deletions bridge/bindings/qjs/bom/window.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ class Window : public EventTarget {
DEFINE_PROTOTYPE_READONLY_PROPERTY(parent);
DEFINE_PROTOTYPE_READONLY_PROPERTY(scrollX);
DEFINE_PROTOTYPE_READONLY_PROPERTY(scrollY);
DEFINE_PROTOTYPE_READONLY_PROPERTY(innerWidth);
DEFINE_PROTOTYPE_READONLY_PROPERTY(innerHeight);
DEFINE_PROTOTYPE_READONLY_PROPERTY(self);

DEFINE_PROTOTYPE_PROPERTY(onerror);
Expand Down
2 changes: 0 additions & 2 deletions bridge/dart_methods.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,6 @@ void registerDartMethods(uint64_t* methodBytes, int32_t length) {
methodPointer->requestAnimationFrame = reinterpret_cast<RequestAnimationFrame>(methodBytes[i++]);
methodPointer->cancelAnimationFrame = reinterpret_cast<CancelAnimationFrame>(methodBytes[i++]);
methodPointer->getScreen = reinterpret_cast<GetScreen>(methodBytes[i++]);
methodPointer->devicePixelRatio = reinterpret_cast<DevicePixelRatio>(methodBytes[i++]);
methodPointer->platformBrightness = reinterpret_cast<PlatformBrightness>(methodBytes[i++]);
methodPointer->toBlob = reinterpret_cast<ToBlob>(methodBytes[i++]);
methodPointer->flushUICommand = reinterpret_cast<FlushUICommand>(methodBytes[i++]);
methodPointer->initWindow = reinterpret_cast<InitWindow>(methodBytes[i++]);
Expand Down
4 changes: 0 additions & 4 deletions bridge/include/dart_methods.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ typedef int32_t (*RequestAnimationFrame)(void* callbackContext, int32_t contextI
typedef void (*ClearTimeout)(int32_t contextId, int32_t timerId);
typedef void (*CancelAnimationFrame)(int32_t contextId, int32_t id);
typedef NativeScreen* (*GetScreen)(int32_t contextId);
typedef double (*DevicePixelRatio)(int32_t contextId);
typedef NativeString* (*PlatformBrightness)(int32_t contextId);
typedef void (*ToBlob)(void* callbackContext, int32_t contextId, AsyncBlobCallback blobCallback, int32_t elementId, double devicePixelRatio);
typedef void (*OnJSError)(int32_t contextId, const char*);
typedef void (*FlushUICommand)();
Expand Down Expand Up @@ -69,8 +67,6 @@ struct DartMethodPointer {
RequestAnimationFrame requestAnimationFrame{nullptr};
CancelAnimationFrame cancelAnimationFrame{nullptr};
GetScreen getScreen{nullptr};
DevicePixelRatio devicePixelRatio{nullptr};
PlatformBrightness platformBrightness{nullptr};
ToBlob toBlob{nullptr};
OnJSError onJsError{nullptr};
MatchImageSnapshot matchImageSnapshot{nullptr};
Expand Down
2 changes: 0 additions & 2 deletions bridge/test/kraken_test_env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -300,8 +300,6 @@ void TEST_mockDartMethods(OnJSError onJSError) {
reinterpret_cast<uint64_t>(TEST_requestAnimationFrame),
reinterpret_cast<uint64_t>(TEST_cancelAnimationFrame),
reinterpret_cast<uint64_t>(TEST_getScreen),
reinterpret_cast<uint64_t>(TEST_devicePixelRatio),
reinterpret_cast<uint64_t>(TEST_platformBrightness),
reinterpret_cast<uint64_t>(TEST_toBlob),
reinterpret_cast<uint64_t>(TEST_flushUICommand),
reinterpret_cast<uint64_t>(TEST_initWindow),
Expand Down
19 changes: 19 additions & 0 deletions integration_tests/specs/window/cssom-view-module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// https://drafts.csswg.org/cssom-view
describe('CSSOM View Module', () => {
it('devicePixelRatio', () => {
expect(window.devicePixelRatio >= 1).toEqual(true);
});

it('innerWidth', () => {
expect(window.innerWidth > 0).toEqual(true);
});

it('innerHeight', () => {
expect(window.innerHeight > 0).toEqual(true);
});

// Custom added property.
it('colorScheme', () => {
expect(typeof window.colorScheme).toEqual('string');
});
});
27 changes: 27 additions & 0 deletions integration_tests/specs/window/screen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
describe('Screen', () => {

it('basic', () => {
expect(screen !== undefined).toEqual(true);
expect(window.screen).toEqual(screen);
});

it('width', () => {
expect(typeof screen.width).toEqual('number');
expect(screen.width > 0).toEqual(true);
});

it('height', () => {
expect(typeof screen.height).toEqual('number');
expect(screen.height > 0).toEqual(true);
});

it('availWidth', () => {
expect(typeof screen.availWidth).toEqual('number');
expect(screen.availWidth > 0).toEqual(true);
});

it('availHeight', () => {
expect(typeof screen.availHeight).toEqual('number');
expect(screen.availHeight > 0).toEqual(true);
});
});
1 change: 1 addition & 0 deletions kraken/lib/dom.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export 'src/dom/document.dart';
export 'src/dom/comment.dart';
export 'src/dom/document_fragment.dart';
export 'src/dom/sliver_manager.dart';
export 'src/dom/screen.dart';
export 'src/dom/element_registry.dart';

// Elements
Expand Down
25 changes: 0 additions & 25 deletions kraken/lib/src/bridge/from_native.dart
Original file line number Diff line number Diff line change
Expand Up @@ -284,29 +284,6 @@ void _cancelAnimationFrame(int contextId, int timerId) {
final Pointer<NativeFunction<NativeCancelAnimationFrame>> _nativeCancelAnimationFrame =
Pointer.fromFunction(_cancelAnimationFrame);

// Register devicePixelRatio
typedef NativeDevicePixelRatio = Double Function();

double _devicePixelRatio() {
return window.devicePixelRatio;
}

final Pointer<NativeFunction<NativeDevicePixelRatio>> _nativeDevicePixelRatio =
Pointer.fromFunction(_devicePixelRatio, 0.0);

// Register platformBrightness
typedef NativePlatformBrightness = Pointer<NativeString> Function();

final Pointer<NativeString> _dark = stringToNativeString('dark');
final Pointer<NativeString> _light = stringToNativeString('light');

Pointer<NativeString> _platformBrightness() {
return window.platformBrightness == Brightness.dark ? _dark : _light;
}

final Pointer<NativeFunction<NativePlatformBrightness>> _nativePlatformBrightness =
Pointer.fromFunction(_platformBrightness);

typedef NativeGetScreen = Pointer<Void> Function();

Pointer<Void> _getScreen() {
Expand Down Expand Up @@ -409,8 +386,6 @@ final List<int> _dartNativeMethods = [
_nativeRequestAnimationFrame.address,
_nativeCancelAnimationFrame.address,
_nativeGetScreen.address,
_nativeDevicePixelRatio.address,
_nativePlatformBrightness.address,
_nativeToBlob.address,
_nativeFlushUICommand.address,
_nativeInitWindow.address,
Expand Down
2 changes: 1 addition & 1 deletion kraken/lib/src/bridge/to_native.dart
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ void emitUIEvent(
Pointer<Void> rawEvent = event.toRaw().cast<Void>();
bool isCustomEvent = event is CustomEvent;
Pointer<NativeString> eventTypeString = stringToNativeString(event.type);
// @TODO: Make Event inhert BindingObject to pass value from bridge to dart.
// @TODO: Make Event inherit BindingObject to pass value from bridge to dart.
int propagationStopped = dispatchEvent(contextId, nativeBindingObject, eventTypeString, rawEvent, isCustomEvent ? 1 : 0);
event.propagationStopped = propagationStopped == 1 ? true : false;
freeNativeString(eventTypeString);
Expand Down
47 changes: 47 additions & 0 deletions kraken/lib/src/dom/screen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2022-present Alibaba Inc. All rights reserved.
* Author: Kraken Team.
*/
import 'dart:ui';

import 'package:kraken/foundation.dart';

// As its name suggests, the Screen interface represents information about the screen of the output device.
// https://drafts.csswg.org/cssom-view/#the-screen-interface
class Screen extends BindingObject {
Screen([BindingContext? context]) : super(context);

@override
getBindingProperty(String key) {
switch (key) {
case 'availWidth': return availWidth;
case 'availHeight': return availHeight;
case 'width': return width;
case 'height': return height;
default: return super.getBindingProperty(key);
}
}

// The availWidth attribute must return the width of the Web-exposed available screen area.
// The Web-exposed available screen area is one of the following:
// - The available area of the rendering surface of the output device, in CSS pixels.
// - The area of the output device, in CSS pixels.
// - The area of the viewport, in CSS pixels.
// @NOTE: Why using physicalSize: in most cases, kraken is integrated into host native app,
// so the size of kraken view is depending on how big is the flutter view, for users
// they can not adjust size of kraken view. The [window.physicalSize] is the size of
// native flutter view. (@zeroling)
int get availWidth => window.physicalSize.width ~/ window.devicePixelRatio;

// The availHeight attribute must return the height of the Web-exposed available screen area.
int get availHeight => window.physicalSize.height ~/ window.devicePixelRatio;

// The width attribute must return the width of the Web-exposed screen area.
// The Web-exposed screen area is one of the following:
// - The area of the output device, in CSS pixels.
// - The area of the viewport, in CSS pixels.
int get width => window.physicalSize.width ~/ window.devicePixelRatio;

// The height attribute must return the height of the Web-exposed screen area.
int get height => window.physicalSize.height ~/ window.devicePixelRatio;
}
47 changes: 36 additions & 11 deletions kraken/lib/src/dom/window.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,39 @@
*/
import 'dart:ui';

import 'package:kraken/bridge.dart';
import 'package:kraken/dom.dart';
import 'package:kraken/foundation.dart';
import 'package:kraken/launcher.dart';
import 'package:kraken/rendering.dart';
import 'package:kraken/module.dart';
import 'package:kraken/bridge.dart';

const String WINDOW = 'WINDOW';

class Window extends EventTarget {
final Document document;
final Screen screen;

@override
EventTarget? get parentEventTarget => null;

Window(BindingContext? context, this.document) : super(context) {
Window(BindingContext? context, this.document)
: screen = Screen(context), super(context) {
window.onPlatformBrightnessChanged = () {
ColorSchemeChangeEvent event = ColorSchemeChangeEvent((window.platformBrightness == Brightness.light) ? 'light' : 'dart');
dispatchEvent(event);
dispatchEvent(ColorSchemeChangeEvent(colorScheme));
};
}

@override
EventTarget? get parentEventTarget => null;

// https://www.w3.org/TR/cssom-view-1/#extensions-to-the-window-interface
@override
getBindingProperty(String key) {
switch (key) {
case 'innerWidth': return innerWidth;
case 'innerHeight': return innerHeight;
case 'scrollX': return scrollX;
case 'scrollY': return scrollY;
case 'screen': return screen;
case 'colorScheme': return colorScheme;
case 'devicePixelRatio': return devicePixelRatio;
default: return super.getBindingProperty(key);
}
}
Expand All @@ -55,9 +61,7 @@ class Window extends EventTarget {
}

void open(String url) {
KrakenController rootController = document.controller.view.rootController;
String? sourceUrl = rootController.url;

String? sourceUrl = document.controller.view.rootController.url;
document.controller.view.handleNavigationAction(sourceUrl, url, KrakenNavigationType.navigate);
}

Expand All @@ -77,6 +81,27 @@ class Window extends EventTarget {
..scrollBy(x, y);
}

String get colorScheme => window.platformBrightness == Brightness.light ? 'light' : 'dark';

double get devicePixelRatio => window.devicePixelRatio;

// The innerWidth/innerHeight attribute must return the viewport width/height
// including the size of a rendered scroll bar (if any), or zero if there is no viewport.
// https://drafts.csswg.org/cssom-view/#dom-window-innerwidth
// This is a read only idl attribute.
int get innerWidth => _viewportSize.width.toInt();
int get innerHeight => _viewportSize.height.toInt();

Size get _viewportSize {
RenderViewportBox? viewport = document.viewport;
if (viewport != null && viewport.hasSize) {
return viewport.size;
} else {
return Size.zero;
}
}


@override
void dispatchEvent(Event event) {
// Events such as EVENT_DOM_CONTENT_LOADED need to ensure that listeners are flushed and registered.
Expand Down

0 comments on commit 100f9e1

Please sign in to comment.