mirror of
https://github.com/servo/servo.git
synced 2025-07-31 11:10:22 +01:00
Auto merge of #7500 - farodin91:viewport, r=jdm
Implement viewport functions for window #1718 @jdm r? closes #6875 <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/7500) <!-- Reviewable:end -->
This commit is contained in:
commit
a844c0b0e8
14 changed files with 466 additions and 63 deletions
|
@ -11,11 +11,11 @@ use surface_map::SurfaceMap;
|
|||
use windowing;
|
||||
use windowing::{MouseWindowEvent, WindowEvent, WindowMethods, WindowNavigateMsg};
|
||||
|
||||
use euclid::Matrix4;
|
||||
use euclid::point::{Point2D, TypedPoint2D};
|
||||
use euclid::rect::{Rect, TypedRect};
|
||||
use euclid::point::TypedPoint2D;
|
||||
use euclid::rect::TypedRect;
|
||||
use euclid::scale_factor::ScaleFactor;
|
||||
use euclid::size::{Size2D, TypedSize2D};
|
||||
use euclid::size::TypedSize2D;
|
||||
use euclid::{Size2D, Point2D, Rect, Matrix4};
|
||||
use gfx::paint_task::{ChromeToPaintMsg, PaintRequest};
|
||||
use gfx_traits::color;
|
||||
use gleam::gl;
|
||||
|
@ -390,7 +390,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
self.send_buffer_requests_for_all_layers();
|
||||
}
|
||||
|
||||
(Msg::GetNativeDisplay(chan), ShutdownState::NotShuttingDown) => {
|
||||
(Msg::GetNativeDisplay(chan),
|
||||
ShutdownState::NotShuttingDown) => {
|
||||
chan.send(Some(self.native_display.clone())).unwrap();
|
||||
}
|
||||
|
||||
|
@ -415,11 +416,27 @@ impl<Window: WindowMethods> IOCompositor<Window> {
|
|||
self.surface_map.insert_surfaces(&self.native_display, native_surfaces);
|
||||
}
|
||||
|
||||
(Msg::ScrollFragmentPoint(pipeline_id, layer_id, point),
|
||||
(Msg::ScrollFragmentPoint(pipeline_id, layer_id, point, _),
|
||||
ShutdownState::NotShuttingDown) => {
|
||||
self.scroll_fragment_to_point(pipeline_id, layer_id, point);
|
||||
}
|
||||
|
||||
(Msg::MoveTo(point),
|
||||
ShutdownState::NotShuttingDown) => {
|
||||
self.window.set_position(point);
|
||||
}
|
||||
|
||||
(Msg::ResizeTo(size),
|
||||
ShutdownState::NotShuttingDown) => {
|
||||
self.window.set_inner_size(size);
|
||||
}
|
||||
|
||||
(Msg::GetClientWindow(send),
|
||||
ShutdownState::NotShuttingDown) => {
|
||||
let rect = self.window.client_window();
|
||||
send.send(rect).unwrap();
|
||||
}
|
||||
|
||||
(Msg::Status(message), ShutdownState::NotShuttingDown) => {
|
||||
self.window.status(message);
|
||||
}
|
||||
|
|
|
@ -11,8 +11,7 @@ use compositor;
|
|||
use headless;
|
||||
use windowing::{WindowEvent, WindowMethods};
|
||||
|
||||
use euclid::point::Point2D;
|
||||
use euclid::rect::Rect;
|
||||
use euclid::{Size2D, Point2D, Rect};
|
||||
use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||||
use layers::layers::{BufferRequest, LayerBufferSet};
|
||||
use layers::platform::surface::{NativeDisplay, NativeSurface};
|
||||
|
@ -66,8 +65,20 @@ pub fn run_script_listener_thread(compositor_proxy: Box<CompositorProxy + 'stati
|
|||
receiver: IpcReceiver<ScriptToCompositorMsg>) {
|
||||
while let Ok(msg) = receiver.recv() {
|
||||
match msg {
|
||||
ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id, layer_id, point) => {
|
||||
compositor_proxy.send(Msg::ScrollFragmentPoint(pipeline_id, layer_id, point));
|
||||
ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id, layer_id, point, _smooth) => {
|
||||
compositor_proxy.send(Msg::ScrollFragmentPoint(pipeline_id, layer_id, point, _smooth));
|
||||
}
|
||||
|
||||
ScriptToCompositorMsg::GetClientWindow(send) => {
|
||||
compositor_proxy.send(Msg::GetClientWindow(send));
|
||||
}
|
||||
|
||||
ScriptToCompositorMsg::MoveTo(point) => {
|
||||
compositor_proxy.send(Msg::MoveTo(point));
|
||||
}
|
||||
|
||||
ScriptToCompositorMsg::ResizeTo(size) => {
|
||||
compositor_proxy.send(Msg::ResizeTo(size));
|
||||
}
|
||||
|
||||
ScriptToCompositorMsg::Exit => {
|
||||
|
@ -159,7 +170,7 @@ pub enum Msg {
|
|||
/// Alerts the compositor that the specified layer's rect has changed.
|
||||
SetLayerRect(PipelineId, LayerId, Rect<f32>),
|
||||
/// Scroll a page in a window
|
||||
ScrollFragmentPoint(PipelineId, LayerId, Point2D<f32>),
|
||||
ScrollFragmentPoint(PipelineId, LayerId, Point2D<f32>, bool),
|
||||
/// Requests that the compositor assign the painted buffers to the given layers.
|
||||
AssignPaintedBuffers(PipelineId, Epoch, Vec<(LayerId, Box<LayerBufferSet>)>, FrameTreeId),
|
||||
/// Alerts the compositor that the current page has changed its title.
|
||||
|
@ -201,6 +212,12 @@ pub enum Msg {
|
|||
CollectMemoryReports(mem::ReportsChan),
|
||||
/// A status message to be displayed by the browser chrome.
|
||||
Status(Option<String>),
|
||||
/// Get Window Informations size and position
|
||||
GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
|
||||
/// Move the window to a point
|
||||
MoveTo(Point2D<i32>),
|
||||
/// Resize the window to size
|
||||
ResizeTo(Size2D<u32>),
|
||||
}
|
||||
|
||||
impl Debug for Msg {
|
||||
|
@ -232,6 +249,9 @@ impl Debug for Msg {
|
|||
Msg::ReturnUnusedNativeSurfaces(..) => write!(f, "ReturnUnusedNativeSurfaces"),
|
||||
Msg::CollectMemoryReports(..) => write!(f, "CollectMemoryReports"),
|
||||
Msg::Status(..) => write!(f, "Status"),
|
||||
Msg::GetClientWindow(..) => write!(f, "GetClientWindow"),
|
||||
Msg::MoveTo(..) => write!(f, "MoveTo"),
|
||||
Msg::ResizeTo(..) => write!(f, "ResizeTo"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ use compositor_task::{CompositorEventListener, CompositorReceiver, Msg};
|
|||
use windowing::WindowEvent;
|
||||
|
||||
use euclid::scale_factor::ScaleFactor;
|
||||
use euclid::size::Size2D;
|
||||
use euclid::{Size2D, Point2D};
|
||||
use msg::constellation_msg::AnimationState;
|
||||
use msg::constellation_msg::Msg as ConstellationMsg;
|
||||
use msg::constellation_msg::{ConstellationChan, WindowSizeData};
|
||||
|
@ -89,6 +89,11 @@ impl CompositorEventListener for NullCompositor {
|
|||
response_chan.send(()).unwrap();
|
||||
}
|
||||
|
||||
Msg::GetClientWindow(send) => {
|
||||
let rect = (Size2D::zero(), Point2D::zero());
|
||||
send.send(rect).unwrap();
|
||||
}
|
||||
|
||||
Msg::ChangeRunningAnimationsState(pipeline_id, animation_state) => {
|
||||
match animation_state {
|
||||
AnimationState::AnimationsPresent |
|
||||
|
@ -121,6 +126,8 @@ impl CompositorEventListener for NullCompositor {
|
|||
Msg::ViewportConstrained(..) => {}
|
||||
Msg::CreatePng(..) |
|
||||
Msg::PaintTaskExited(..) |
|
||||
Msg::MoveTo(..) |
|
||||
Msg::ResizeTo(..) |
|
||||
Msg::IsReadyToSaveImageReply(..) => {}
|
||||
Msg::NewFavicon(..) => {}
|
||||
Msg::HeadParsed => {}
|
||||
|
|
|
@ -9,6 +9,7 @@ use compositor_task::{CompositorProxy, CompositorReceiver};
|
|||
use euclid::point::TypedPoint2D;
|
||||
use euclid::scale_factor::ScaleFactor;
|
||||
use euclid::size::TypedSize2D;
|
||||
use euclid::{Size2D, Point2D};
|
||||
use layers::geometry::DevicePixel;
|
||||
use layers::platform::surface::NativeDisplay;
|
||||
use msg::constellation_msg::{Key, KeyState, KeyModifiers};
|
||||
|
@ -103,6 +104,13 @@ pub trait WindowMethods {
|
|||
/// Presents the window to the screen (perhaps by page flipping).
|
||||
fn present(&self);
|
||||
|
||||
/// Return the size of the window with head and borders and position of the window values
|
||||
fn client_window(&self) -> (Size2D<u32>, Point2D<i32>);
|
||||
/// Set the size inside of borders and head
|
||||
fn set_inner_size(&self, size: Size2D<u32>);
|
||||
/// Set the window position
|
||||
fn set_position(&self, point: Point2D<i32>);
|
||||
|
||||
/// Sets the page title for the current page.
|
||||
fn set_page_title(&self, title: Option<String>);
|
||||
/// Sets the load data for the current page.
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
use azure::azure_hl::Color;
|
||||
use constellation_msg::{Key, KeyState, KeyModifiers};
|
||||
use euclid::Matrix4;
|
||||
use euclid::point::Point2D;
|
||||
use euclid::rect::Rect;
|
||||
use euclid::{Size2D, Point2D, Rect};
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use layers::layers::{BufferRequest, LayerBufferSet};
|
||||
use layers::platform::surface::NativeDisplay;
|
||||
use std::fmt;
|
||||
|
@ -119,9 +119,11 @@ pub trait PaintListener {
|
|||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
pub enum ScriptToCompositorMsg {
|
||||
ScrollFragmentPoint(PipelineId, LayerId, Point2D<f32>),
|
||||
ScrollFragmentPoint(PipelineId, LayerId, Point2D<f32>, bool),
|
||||
SetTitle(PipelineId, Option<String>),
|
||||
SendKeyEvent(Key, KeyState, KeyModifiers),
|
||||
GetClientWindow(IpcSender<(Size2D<u32>, Point2D<i32>)>),
|
||||
MoveTo(Point2D<i32>),
|
||||
ResizeTo(Size2D<u32>),
|
||||
Exit,
|
||||
}
|
||||
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
//! The high-level interface from script to constellation. Using this abstract interface helps
|
||||
//! reduce coupling between these two components.
|
||||
|
||||
use compositor_msg::Epoch;
|
||||
|
||||
use canvas_traits::CanvasMsg;
|
||||
use compositor_msg::Epoch;
|
||||
use euclid::rect::Rect;
|
||||
use euclid::scale_factor::ScaleFactor;
|
||||
use euclid::size::{Size2D, TypedSize2D};
|
||||
|
|
|
@ -105,36 +105,53 @@ partial interface Window {
|
|||
CSSStyleDeclaration getComputedStyle(Element elt, optional DOMString pseudoElt);
|
||||
};
|
||||
|
||||
// http://dev.w3.org/csswg/cssom-view/#extensions-to-the-window-interface
|
||||
enum ScrollBehavior { "auto", "instant", "smooth" };
|
||||
|
||||
// http://dev.w3.org/csswg/cssom-view/#extensions-to-the-window-interface
|
||||
dictionary ScrollOptions {
|
||||
ScrollBehavior behavior = "auto";
|
||||
};
|
||||
|
||||
// http://dev.w3.org/csswg/cssom-view/#extensions-to-the-window-interface
|
||||
dictionary ScrollToOptions : ScrollOptions {
|
||||
unrestricted double left;
|
||||
unrestricted double top;
|
||||
};
|
||||
|
||||
// http://dev.w3.org/csswg/cssom-view/#extensions-to-the-window-interface
|
||||
partial interface Window {
|
||||
//MediaQueryList matchMedia(DOMString query);
|
||||
[SameObject] readonly attribute Screen screen;
|
||||
|
||||
// browsing context
|
||||
//void moveTo(double x, double y);
|
||||
//void moveBy(double x, double y);
|
||||
//void resizeTo(double x, double y);
|
||||
//void resizeBy(double x, double y);
|
||||
void moveTo(long x, long y);
|
||||
void moveBy(long x, long y);
|
||||
void resizeTo(long x, long y);
|
||||
void resizeBy(long x, long y);
|
||||
|
||||
// viewport
|
||||
//readonly attribute double innerWidth;
|
||||
//readonly attribute double innerHeight;
|
||||
readonly attribute long innerWidth;
|
||||
readonly attribute long innerHeight;
|
||||
|
||||
// viewport scrolling
|
||||
//readonly attribute double scrollX;
|
||||
//readonly attribute double pageXOffset;
|
||||
//readonly attribute double scrollY;
|
||||
//readonly attribute double pageYOffset;
|
||||
//void scroll(double x, double y, optional ScrollOptions options);
|
||||
//void scrollTo(double x, double y, optional ScrollOptions options);
|
||||
//void scrollBy(double x, double y, optional ScrollOptions options);
|
||||
readonly attribute long scrollX;
|
||||
readonly attribute long pageXOffset;
|
||||
readonly attribute long scrollY;
|
||||
readonly attribute long pageYOffset;
|
||||
void scroll(optional ScrollToOptions options);
|
||||
void scroll(unrestricted double x, unrestricted double y);
|
||||
void scrollTo(optional ScrollToOptions options);
|
||||
void scrollTo(unrestricted double x, unrestricted double y);
|
||||
void scrollBy(optional ScrollToOptions options);
|
||||
void scrollBy(unrestricted double x, unrestricted double y);
|
||||
|
||||
// client
|
||||
//readonly attribute double screenX;
|
||||
//readonly attribute double screenY;
|
||||
//readonly attribute double outerWidth;
|
||||
//readonly attribute double outerHeight;
|
||||
//readonly attribute double devicePixelRatio;
|
||||
readonly attribute long screenX;
|
||||
readonly attribute long screenY;
|
||||
readonly attribute long outerWidth;
|
||||
readonly attribute long outerHeight;
|
||||
readonly attribute double devicePixelRatio;
|
||||
};
|
||||
|
||||
// Proprietary extensions.
|
||||
|
|
|
@ -7,6 +7,7 @@ use dom::bindings::cell::DOMRefCell;
|
|||
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
|
||||
use dom::bindings::codegen::Bindings::EventHandlerBinding::{OnErrorEventHandlerNonNull, EventHandlerNonNull};
|
||||
use dom::bindings::codegen::Bindings::FunctionBinding::Function;
|
||||
use dom::bindings::codegen::Bindings::WindowBinding::{ScrollToOptions, ScrollBehavior};
|
||||
use dom::bindings::codegen::Bindings::WindowBinding::{self, WindowMethods, FrameRequestCallback};
|
||||
use dom::bindings::codegen::InheritTypes::{NodeCast, ElementCast, EventTargetCast, WindowDerived};
|
||||
use dom::bindings::error::Error::InvalidCharacter;
|
||||
|
@ -40,7 +41,7 @@ use timers::{IsInterval, TimerId, TimerManager, TimerCallback};
|
|||
use webdriver_handlers::jsval_to_webdriver;
|
||||
|
||||
use devtools_traits::{ScriptToDevtoolsControlMsg, TimelineMarker, TimelineMarkerType};
|
||||
use msg::compositor_msg::ScriptToCompositorMsg;
|
||||
use msg::compositor_msg::{ScriptToCompositorMsg, LayerId};
|
||||
use msg::constellation_msg::{LoadData, PipelineId, SubpageId, ConstellationChan, WindowSizeData, WorkerId};
|
||||
use msg::webdriver_msg::{WebDriverJSError, WebDriverJSResult};
|
||||
use net_traits::ResourceTask;
|
||||
|
@ -52,8 +53,9 @@ use util::geometry::{self, Au, MAX_RECT};
|
|||
use util::str::{DOMString, HTML_SPACE_CHARACTERS};
|
||||
use util::{breakpoint, opts};
|
||||
|
||||
use euclid::scale_factor::ScaleFactor;
|
||||
use euclid::{Point2D, Rect, Size2D};
|
||||
use ipc_channel::ipc::IpcSender;
|
||||
use ipc_channel::ipc::{self, IpcSender};
|
||||
use js::jsapi::{Evaluate2, MutableHandleValue};
|
||||
use js::jsapi::{JSContext, HandleValue};
|
||||
use js::jsapi::{JS_GC, JS_GetRuntime, JSAutoCompartment, JSAutoRequest};
|
||||
|
@ -63,6 +65,7 @@ use selectors::parser::PseudoElement;
|
|||
use url::Url;
|
||||
|
||||
use libc;
|
||||
use num::traits::ToPrimitive;
|
||||
use rustc_serialize::base64::{FromBase64, ToBase64, STANDARD};
|
||||
use std::ascii::AsciiExt;
|
||||
use std::borrow::ToOwned;
|
||||
|
@ -103,6 +106,8 @@ pub enum ReflowReason {
|
|||
RequestAnimationFrame,
|
||||
}
|
||||
|
||||
pub type ScrollPoint = Point2D<Au>;
|
||||
|
||||
#[dom_struct]
|
||||
pub struct Window {
|
||||
eventtarget: EventTarget,
|
||||
|
@ -213,6 +218,8 @@ pub struct Window {
|
|||
|
||||
/// The current state of the window object
|
||||
current_state: Cell<WindowState>,
|
||||
|
||||
current_viewport: Cell<Rect<Au>>
|
||||
}
|
||||
|
||||
impl Window {
|
||||
|
@ -603,8 +610,152 @@ impl WindowMethods for Window {
|
|||
// Step 5.
|
||||
CSSStyleDeclaration::new(self, element, pseudo, CSSModificationAccess::Readonly)
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-innerheight
|
||||
//TODO Include Scrollbar
|
||||
fn InnerHeight(&self) -> i32 {
|
||||
let size = self.window_size.get();
|
||||
match size {
|
||||
Some(e) => e.visible_viewport.height.get().to_i32().unwrap_or(0),
|
||||
None => 0
|
||||
}
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-innerwidth
|
||||
//TODO Include Scrollbar
|
||||
fn InnerWidth(&self) -> i32 {
|
||||
let size = self.window_size.get();
|
||||
match size {
|
||||
Some(e) => e.visible_viewport.width.get().to_i32().unwrap_or(0),
|
||||
None => 0
|
||||
}
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-scrollx
|
||||
fn ScrollX(&self) -> i32 {
|
||||
self.current_viewport.get().origin.x.to_px()
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-pagexoffset
|
||||
fn PageXOffset(&self) -> i32 {
|
||||
self.ScrollX()
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-scrolly
|
||||
fn ScrollY(&self) -> i32 {
|
||||
self.current_viewport.get().origin.y.to_px()
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-pageyoffset
|
||||
fn PageYOffset(&self) -> i32 {
|
||||
self.ScrollY()
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-scroll
|
||||
fn Scroll(&self, options: &ScrollToOptions) {
|
||||
// Step 1
|
||||
let left = options.left.unwrap_or(0.0f64);
|
||||
let top = options.top.unwrap_or(0.0f64);
|
||||
self.scroll(left, top, options.parent.behavior);
|
||||
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-scroll
|
||||
fn Scroll_(&self, x: f64, y: f64) {
|
||||
self.scroll(x, y, ScrollBehavior::Auto);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-scrollto
|
||||
fn ScrollTo(&self, options: &ScrollToOptions) {
|
||||
self.Scroll(options);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-scrollto
|
||||
fn ScrollTo_(&self, x: f64, y: f64) {
|
||||
self.scroll(x, y, ScrollBehavior::Auto);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-scrollby
|
||||
fn ScrollBy(&self, options: &ScrollToOptions) {
|
||||
// Step 1
|
||||
let x = options.left.unwrap_or(0.0f64);
|
||||
let y = options.top.unwrap_or(0.0f64);
|
||||
self.ScrollBy_(x, y, );
|
||||
self.scroll(x, y, options.parent.behavior);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-scrollby
|
||||
fn ScrollBy_(&self, x: f64, y: f64) {
|
||||
// Step 3
|
||||
let left = x + self.ScrollX() as f64;
|
||||
// Step 4
|
||||
let top = y + self.ScrollY() as f64;
|
||||
|
||||
// Step 5
|
||||
self.scroll(left, top, ScrollBehavior::Auto);
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-resizeto
|
||||
fn ResizeTo(&self, x: i32, y: i32) {
|
||||
// Step 1
|
||||
//TODO determine if this operation is allowed
|
||||
let size = Size2D::new(x.to_u32().unwrap_or(1), y.to_u32().unwrap_or(1));
|
||||
self.compositor.send(ScriptToCompositorMsg::ResizeTo(size)).unwrap()
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-resizeby
|
||||
fn ResizeBy(&self, x: i32, y: i32) {
|
||||
let (size, _) = self.client_window();
|
||||
// Step 1
|
||||
self.ResizeTo(x + size.width.to_i32().unwrap_or(1), y + size.height.to_i32().unwrap_or(1))
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-moveto
|
||||
fn MoveTo(&self, x: i32, y: i32) {
|
||||
// Step 1
|
||||
//TODO determine if this operation is allowed
|
||||
let point = Point2D::new(x, y);
|
||||
self.compositor.send(ScriptToCompositorMsg::MoveTo(point)).unwrap()
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-moveby
|
||||
fn MoveBy(&self, x: i32, y: i32) {
|
||||
let (_, origin) = self.client_window();
|
||||
// Step 1
|
||||
self.MoveTo(x + origin.x, y + origin.y)
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-screenx
|
||||
fn ScreenX(&self) -> i32 {
|
||||
let (_, origin) = self.client_window();
|
||||
origin.x
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-screeny
|
||||
fn ScreenY(&self) -> i32 {
|
||||
let (_, origin) = self.client_window();
|
||||
origin.y
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-outerheight
|
||||
fn OuterHeight(&self) -> i32 {
|
||||
let (size, _) = self.client_window();
|
||||
size.height.to_i32().unwrap_or(1)
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-outerwidth
|
||||
fn OuterWidth(&self) -> i32 {
|
||||
let (size, _) = self.client_window();
|
||||
size.width.to_i32().unwrap_or(1)
|
||||
}
|
||||
|
||||
// https://drafts.csswg.org/cssom-view/#dom-window-devicepixelratio
|
||||
fn DevicePixelRatio(&self) -> Finite<f64> {
|
||||
let dpr = self.window_size.get()
|
||||
.map(|data| data.device_pixel_ratio).unwrap_or(ScaleFactor::new(1.0f32)).get();
|
||||
Finite::wrap(dpr as f64)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ScriptHelpers {
|
||||
fn evaluate_js_on_global_with_result(self, code: &str,
|
||||
|
@ -664,6 +815,83 @@ impl Window {
|
|||
*self.browsing_context.borrow_mut() = None;
|
||||
}
|
||||
|
||||
/// https://drafts.csswg.org/cssom-view/#dom-window-scroll
|
||||
pub fn scroll(&self, x_: f64, y_: f64, behavior: ScrollBehavior) {
|
||||
// Step 3
|
||||
let xfinite = if x_.is_finite() { x_ } else { 0.0f64 };
|
||||
let yfinite = if y_.is_finite() { y_ } else { 0.0f64 };
|
||||
|
||||
// Step 4
|
||||
if self.window_size.get().is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 5
|
||||
//TODO remove scrollbar width
|
||||
let width = self.InnerWidth() as f64;
|
||||
// Step 6
|
||||
//TODO remove scrollbar width
|
||||
let height = self.InnerHeight() as f64;
|
||||
|
||||
// Step 7 & 8
|
||||
//TODO use overflow direction
|
||||
let body = self.Document().GetBody();
|
||||
let (x, y) = match body {
|
||||
Some(e) => {
|
||||
let node = NodeCast::from_ref(e.r());
|
||||
let content_size = node.get_bounding_content_box();
|
||||
|
||||
let content_height = content_size.size.height.to_f64_px();
|
||||
let content_width = content_size.size.width.to_f64_px();
|
||||
(xfinite.max(0.0f64).min(content_width - width),
|
||||
yfinite.max(0.0f64).min(content_height - height))
|
||||
},
|
||||
None => {
|
||||
(xfinite.max(0.0f64), yfinite.max(0.0f64))
|
||||
}
|
||||
};
|
||||
|
||||
// Step 10
|
||||
//TODO handling ongoing smoth scrolling
|
||||
if x == self.ScrollX() as f64 && y == self.ScrollY() as f64 {
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO Step 11
|
||||
//let document = self.Document();
|
||||
// Step 12
|
||||
self.perform_a_scroll(x.to_f32().unwrap_or(0.0f32), y.to_f32().unwrap_or(0.0f32), behavior, None);
|
||||
}
|
||||
|
||||
/// https://drafts.csswg.org/cssom-view/#perform-a-scroll
|
||||
pub fn perform_a_scroll(&self, x: f32, y: f32, behavior: ScrollBehavior, element: Option<&Element>) {
|
||||
//TODO Step 1
|
||||
let point = Point2D::new(x, y);
|
||||
let smooth = match behavior {
|
||||
ScrollBehavior::Auto => {
|
||||
element.map(|_element| {
|
||||
// TODO check computed scroll-behaviour CSS property
|
||||
true
|
||||
}).unwrap_or(false)
|
||||
}
|
||||
ScrollBehavior::Instant => false,
|
||||
ScrollBehavior::Smooth => true
|
||||
};
|
||||
|
||||
// TODO (farodin91): Raise an event to stop the current_viewport
|
||||
let size = self.current_viewport.get().size;
|
||||
self.current_viewport.set(Rect::new(Point2D::new(Au::from_f32_px(x), Au::from_f32_px(y)), size));
|
||||
|
||||
self.compositor.send(ScriptToCompositorMsg::ScrollFragmentPoint(
|
||||
self.pipeline(), LayerId::null(), point, smooth)).unwrap()
|
||||
}
|
||||
|
||||
pub fn client_window(&self) -> (Size2D<u32>, Point2D<i32>) {
|
||||
let (send, recv) = ipc::channel::<(Size2D<u32>, Point2D<i32>)>().unwrap();
|
||||
self.compositor.send(ScriptToCompositorMsg::GetClientWindow(send)).unwrap();
|
||||
recv.recv().unwrap_or((Size2D::zero(), Point2D::zero()))
|
||||
}
|
||||
|
||||
/// Reflows the page unconditionally. This method will wait for the layout thread to complete
|
||||
/// (but see the `TODO` below). If there is no window size yet, the page is presumed invisible
|
||||
/// and no reflow is performed.
|
||||
|
@ -941,6 +1169,8 @@ impl Window {
|
|||
}
|
||||
|
||||
pub fn set_page_clip_rect_with_new_viewport(&self, viewport: Rect<f32>) -> bool {
|
||||
let rect = geometry::f32_rect_to_au_rect(viewport.clone());
|
||||
self.current_viewport.set(rect);
|
||||
// We use a clipping rectangle that is five times the size of the of the viewport,
|
||||
// so that we don't collect display list items for areas too far outside the viewport,
|
||||
// but also don't trigger reflows every time the viewport changes.
|
||||
|
@ -1095,6 +1325,7 @@ impl Window {
|
|||
layout_rpc: layout_rpc,
|
||||
layout_join_port: DOMRefCell::new(None),
|
||||
window_size: Cell::new(window_size),
|
||||
current_viewport: Cell::new(Rect::zero()),
|
||||
pending_reflow_count: Cell::new(0),
|
||||
current_state: Cell::new(WindowState::Alive),
|
||||
|
||||
|
|
|
@ -1722,7 +1722,7 @@ impl ScriptTask {
|
|||
// layer the element belongs to, and have it send the scroll message to the
|
||||
// compositor.
|
||||
self.compositor.borrow_mut().send(ScriptToCompositorMsg::ScrollFragmentPoint(
|
||||
pipeline_id, LayerId::null(), point)).unwrap();
|
||||
pipeline_id, LayerId::null(), point, false)).unwrap();
|
||||
}
|
||||
|
||||
/// Reflows non-incrementally, rebuilding the entire layout tree in the process.
|
||||
|
|
|
@ -20,6 +20,8 @@ use wrappers::CefWrap;
|
|||
|
||||
use compositing::compositor_task::{self, CompositorProxy, CompositorReceiver};
|
||||
use compositing::windowing::{WindowEvent, WindowMethods};
|
||||
use euclid::point::Point2D;
|
||||
use euclid::rect::Rect;
|
||||
use euclid::scale_factor::ScaleFactor;
|
||||
use euclid::size::{Size2D, TypedSize2D};
|
||||
use gleam::gl;
|
||||
|
@ -223,6 +225,22 @@ impl WindowMethods for Window {
|
|||
}
|
||||
}
|
||||
|
||||
fn client_window(&self) -> (Size2D<u32>, Point2D<i32>) {
|
||||
let size = self.size().to_untyped();
|
||||
let width = size.width as u32;
|
||||
let height = size.height as u32;
|
||||
//TODO get real window position
|
||||
(Size2D::new(width, height), Point2D::zero())
|
||||
}
|
||||
|
||||
fn set_inner_size(&self, size: Size2D<u32>) {
|
||||
|
||||
}
|
||||
|
||||
fn set_position(&self, point: Point2D<i32>) {
|
||||
|
||||
}
|
||||
|
||||
fn present(&self) {
|
||||
let browser = self.cef_browser.borrow();
|
||||
match *browser {
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
use compositing::compositor_task::{self, CompositorProxy, CompositorReceiver};
|
||||
use compositing::windowing::{WindowEvent, WindowMethods};
|
||||
use euclid::scale_factor::ScaleFactor;
|
||||
use euclid::size::{Size2D, TypedSize2D};
|
||||
use euclid::size::TypedSize2D;
|
||||
use euclid::{Size2D, Point2D};
|
||||
use gleam::gl;
|
||||
use glutin;
|
||||
use layers::geometry::DevicePixel;
|
||||
|
@ -25,8 +26,6 @@ use NestedEventLoopListener;
|
|||
#[cfg(feature = "window")]
|
||||
use compositing::windowing::{MouseWindowEvent, WindowNavigateMsg};
|
||||
#[cfg(feature = "window")]
|
||||
use euclid::point::Point2D;
|
||||
#[cfg(feature = "window")]
|
||||
use glutin::{Api, ElementState, Event, GlRequest, MouseButton, VirtualKeyCode, MouseScrollDelta};
|
||||
#[cfg(feature = "window")]
|
||||
use msg::constellation_msg::{KeyState, NONE, CONTROL, SHIFT, ALT, SUPER};
|
||||
|
@ -521,6 +520,22 @@ impl WindowMethods for Window {
|
|||
Size2D::typed(width as f32, height as f32)
|
||||
}
|
||||
|
||||
fn client_window(&self) -> (Size2D<u32>, Point2D<i32>) {
|
||||
let (width, height) = self.window.get_outer_size().unwrap();
|
||||
let size = Size2D::new(width, height);
|
||||
let (x, y) = self.window.get_position().unwrap();
|
||||
let origin = Point2D::new(x as i32, y as i32);
|
||||
(size, origin)
|
||||
}
|
||||
|
||||
fn set_inner_size(&self, size: Size2D<u32>) {
|
||||
self.window.set_inner_size(size.width as u32, size.height as u32)
|
||||
}
|
||||
|
||||
fn set_position(&self, point: Point2D<i32>) {
|
||||
self.window.set_position(point.x, point.y)
|
||||
}
|
||||
|
||||
fn present(&self) {
|
||||
self.window.swap_buffers().unwrap();
|
||||
}
|
||||
|
@ -748,6 +763,20 @@ impl WindowMethods for Window {
|
|||
fn present(&self) {
|
||||
}
|
||||
|
||||
fn set_inner_size(&self, _: Size2D<u32>) {
|
||||
|
||||
}
|
||||
|
||||
fn set_position(&self, _: Point2D<i32>) {
|
||||
|
||||
}
|
||||
|
||||
fn client_window(&self) -> (Size2D<u32>, Point2D<i32>) {
|
||||
let width = self.width;
|
||||
let height = self.height;
|
||||
(Size2D::new(width, height), Point2D::zero())
|
||||
}
|
||||
|
||||
fn create_compositor_channel(_: &Option<Rc<Window>>)
|
||||
-> (Box<CompositorProxy + Send>, Box<CompositorReceiver>) {
|
||||
let (sender, receiver) = channel();
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
use compositing::compositor_task::{self, CompositorProxy, CompositorReceiver};
|
||||
use compositing::windowing::{WindowEvent, WindowMethods};
|
||||
use euclid::point::Point2D;
|
||||
use euclid::scale_factor::ScaleFactor;
|
||||
use euclid::size::{Size2D, TypedSize2D};
|
||||
use gleam::gl;
|
||||
|
@ -790,6 +791,20 @@ impl WindowMethods for Window {
|
|||
Size2D::typed(self.width as f32, self.height as f32)
|
||||
}
|
||||
|
||||
fn client_window(&self) -> (Size2D<u32>, Point2D<i32>) {
|
||||
let width = self.width as u32;
|
||||
let height = self.height as u32;
|
||||
(Size2D::new(width, height), Point2D::zero())
|
||||
}
|
||||
|
||||
fn set_inner_size(&self, _: Size2D<u32>) {
|
||||
|
||||
}
|
||||
|
||||
fn set_position(&self, _: Point2D<i32>) {
|
||||
|
||||
}
|
||||
|
||||
/// Presents the window to the screen (perhaps by page flipping).
|
||||
fn present(&self) {
|
||||
let _ = egl::SwapBuffers(self.dpy, self.surf);
|
||||
|
@ -870,4 +885,3 @@ impl CompositorProxy for GonkCompositorProxy {
|
|||
} as Box<CompositorProxy + Send>
|
||||
}
|
||||
}
|
||||
|
||||
|
|
42
tests/html/viewport.html
Normal file
42
tests/html/viewport.html
Normal file
|
@ -0,0 +1,42 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test innerHeight</title>
|
||||
<script type="text/javascript">
|
||||
function show(){
|
||||
console.log("innerHeight: "+ window.innerHeight);
|
||||
console.log("innerWidth: "+ window.innerWidth);
|
||||
console.log("ScrollY: "+ window.scrollY);
|
||||
console.log("ScrollX: "+ window.scrollX);
|
||||
console.log("outerHeight: "+ window.outerHeight);
|
||||
console.log("outerWidth: "+ window.outerWidth);
|
||||
console.log("screenY: "+ window.screenY);
|
||||
console.log("screenX: "+ window.screenX);
|
||||
}
|
||||
function test_scroll(){
|
||||
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<button onclick="show();">Test</button>
|
||||
<button onclick="window.scroll(0,100);">Scroll</button>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<br/>
|
||||
<button onclick="window.moveTo(100,10);">Move</button>
|
||||
<button onclick="window.scroll(0,10);">Scroll 2</button>
|
||||
<div style="background-color: #b0c4de; height:1000px; width:800px;"/>
|
||||
<button onclick="show();">Test</button>
|
||||
</body>
|
||||
</html>
|
|
@ -377,4 +377,3 @@
|
|||
|
||||
[Window replaceable attribute: devicePixelRatio]
|
||||
expected: FAIL
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue