mirror of
https://github.com/servo/servo.git
synced 2025-06-17 12:54:28 +00:00
Implement getters and setters for img width and height properties
This commit is contained in:
parent
7fb96c1574
commit
42c6a53148
9 changed files with 174 additions and 25 deletions
|
@ -426,9 +426,7 @@ impl RenderBox {
|
||||||
GenericRenderBoxClass(*) => Au(0),
|
GenericRenderBoxClass(*) => Au(0),
|
||||||
|
|
||||||
ImageRenderBoxClass(image_box) => {
|
ImageRenderBoxClass(image_box) => {
|
||||||
// TODO: Consult the CSS `width` property as well as margins and borders.
|
self.image_width(image_box)
|
||||||
// TODO: If the image isn't available, consult `width`.
|
|
||||||
Au::from_px(image_box.image.get_size().unwrap_or_default(Size2D(0, 0)).width)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextRenderBoxClass(text_box) => {
|
TextRenderBoxClass(text_box) => {
|
||||||
|
@ -449,7 +447,7 @@ impl RenderBox {
|
||||||
GenericRenderBoxClass(*) => Au(0),
|
GenericRenderBoxClass(*) => Au(0),
|
||||||
|
|
||||||
ImageRenderBoxClass(image_box) => {
|
ImageRenderBoxClass(image_box) => {
|
||||||
Au::from_px(image_box.image.get_size().unwrap_or_default(Size2D(0, 0)).width)
|
self.image_width(image_box)
|
||||||
}
|
}
|
||||||
|
|
||||||
TextRenderBoxClass(text_box) => {
|
TextRenderBoxClass(text_box) => {
|
||||||
|
@ -472,6 +470,58 @@ impl RenderBox {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate the width of an image, accounting for the width attribute
|
||||||
|
// TODO: This could probably go somewhere else
|
||||||
|
pub fn image_width(&self, image_box: @mut ImageRenderBox) -> Au {
|
||||||
|
let attr_width: Option<int> = do self.with_base |base| {
|
||||||
|
do base.node.with_imm_element |elt| {
|
||||||
|
match elt.get_attr("width") {
|
||||||
|
Some(width) => {
|
||||||
|
FromStr::from_str(width)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Consult margins and borders?
|
||||||
|
let px_width = if attr_width.is_some() {
|
||||||
|
attr_width.unwrap()
|
||||||
|
} else {
|
||||||
|
image_box.image.get_size().unwrap_or_default(Size2D(0, 0)).width
|
||||||
|
};
|
||||||
|
|
||||||
|
Au::from_px(px_width)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the height of an image, accounting for the height attribute
|
||||||
|
// TODO: This could probably go somewhere else
|
||||||
|
pub fn image_height(&self, image_box: @mut ImageRenderBox) -> Au {
|
||||||
|
let attr_height: Option<int> = do self.with_base |base| {
|
||||||
|
do base.node.with_imm_element |elt| {
|
||||||
|
match elt.get_attr("height") {
|
||||||
|
Some(height) => {
|
||||||
|
FromStr::from_str(height)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Consult margins and borders?
|
||||||
|
let px_height = if attr_height.is_some() {
|
||||||
|
attr_height.unwrap()
|
||||||
|
} else {
|
||||||
|
image_box.image.get_size().unwrap_or_default(Size2D(0, 0)).height
|
||||||
|
};
|
||||||
|
|
||||||
|
Au::from_px(px_height)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the amount of left and right "fringe" used by this box. This is based on margins,
|
/// Returns the amount of left and right "fringe" used by this box. This is based on margins,
|
||||||
/// borders, padding, and width.
|
/// borders, padding, and width.
|
||||||
pub fn get_used_width(&self) -> (Au, Au) {
|
pub fn get_used_width(&self) -> (Au, Au) {
|
||||||
|
|
|
@ -553,8 +553,7 @@ impl InlineFlowData {
|
||||||
for &box in this.boxes.iter() {
|
for &box in this.boxes.iter() {
|
||||||
match box {
|
match box {
|
||||||
ImageRenderBoxClass(image_box) => {
|
ImageRenderBoxClass(image_box) => {
|
||||||
let size = image_box.image.get_size();
|
let width = box.image_width(image_box);
|
||||||
let width = Au::from_px(size.unwrap_or_default(Size2D(0, 0)).width);
|
|
||||||
image_box.base.position.size.width = width;
|
image_box.base.position.size.width = width;
|
||||||
}
|
}
|
||||||
TextRenderBoxClass(_) => {
|
TextRenderBoxClass(_) => {
|
||||||
|
@ -684,8 +683,7 @@ impl InlineFlowData {
|
||||||
|
|
||||||
let (top_from_base, bottom_from_base, ascent) = match cur_box {
|
let (top_from_base, bottom_from_base, ascent) = match cur_box {
|
||||||
ImageRenderBoxClass(image_box) => {
|
ImageRenderBoxClass(image_box) => {
|
||||||
let size = image_box.image.get_size();
|
let mut height = cur_box.image_height(image_box);
|
||||||
let mut height = Au::from_px(size.unwrap_or_default(Size2D(0, 0)).height);
|
|
||||||
|
|
||||||
// TODO: margin, border, padding's top and bottom should be calculated in advance,
|
// TODO: margin, border, padding's top and bottom should be calculated in advance,
|
||||||
// since baseline of image is bottom margin edge.
|
// since baseline of image is bottom margin edge.
|
||||||
|
|
|
@ -547,12 +547,13 @@ def addExternalIface(iface, nativeType=None, headerFile=None, pointerType=None):
|
||||||
domInterface['pointerType'] = pointerType
|
domInterface['pointerType'] = pointerType
|
||||||
DOMInterfaces[iface] = domInterface
|
DOMInterfaces[iface] = domInterface
|
||||||
|
|
||||||
def addHTMLElement(element, concrete=None):
|
def addHTMLElement(element, concrete=None, needsAbstract=[]):
|
||||||
DOMInterfaces[element] = {
|
DOMInterfaces[element] = {
|
||||||
'nativeType': 'AbstractNode<ScriptView>',
|
'nativeType': 'AbstractNode<ScriptView>',
|
||||||
'pointerType': '',
|
'pointerType': '',
|
||||||
'concreteType': concrete if concrete else element,
|
'concreteType': concrete if concrete else element,
|
||||||
'customTrace': 'trace'
|
'customTrace': 'trace',
|
||||||
|
'needsAbstract': needsAbstract
|
||||||
}
|
}
|
||||||
|
|
||||||
addHTMLElement('Comment')
|
addHTMLElement('Comment')
|
||||||
|
@ -585,7 +586,7 @@ addHTMLElement('HTMLHeadingElement')
|
||||||
addHTMLElement('HTMLHtmlElement')
|
addHTMLElement('HTMLHtmlElement')
|
||||||
addHTMLElement('HTMLHRElement')
|
addHTMLElement('HTMLHRElement')
|
||||||
addHTMLElement('HTMLIFrameElement')
|
addHTMLElement('HTMLIFrameElement')
|
||||||
addHTMLElement('HTMLImageElement')
|
addHTMLElement('HTMLImageElement', needsAbstract=['width', 'height'])
|
||||||
addHTMLElement('HTMLInputElement')
|
addHTMLElement('HTMLInputElement')
|
||||||
addHTMLElement('HTMLLabelElement')
|
addHTMLElement('HTMLLabelElement')
|
||||||
addHTMLElement('HTMLLegendElement')
|
addHTMLElement('HTMLLegendElement')
|
||||||
|
|
|
@ -3115,8 +3115,8 @@ class CGGetterCall(CGPerSignatureCall):
|
||||||
A class to generate a native object getter call for a particular IDL
|
A class to generate a native object getter call for a particular IDL
|
||||||
getter.
|
getter.
|
||||||
"""
|
"""
|
||||||
def __init__(self, returnType, nativeMethodName, descriptor, attr):
|
def __init__(self, argsPre, returnType, nativeMethodName, descriptor, attr):
|
||||||
CGPerSignatureCall.__init__(self, returnType, [], [],
|
CGPerSignatureCall.__init__(self, returnType, argsPre, [],
|
||||||
nativeMethodName, False, descriptor,
|
nativeMethodName, False, descriptor,
|
||||||
attr, getter=True)
|
attr, getter=True)
|
||||||
|
|
||||||
|
@ -3290,6 +3290,8 @@ class CGSpecializedGetter(CGAbstractExternMethod):
|
||||||
def definition_body(self):
|
def definition_body(self):
|
||||||
name = self.attr.identifier.name
|
name = self.attr.identifier.name
|
||||||
nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
|
nativeName = MakeNativeName(self.descriptor.binaryNames.get(name, name))
|
||||||
|
extraPre = ''
|
||||||
|
argsPre = []
|
||||||
# resultOutParam does not depend on whether resultAlreadyAddRefed is set
|
# resultOutParam does not depend on whether resultAlreadyAddRefed is set
|
||||||
(_, resultOutParam) = getRetvalDeclarationForType(self.attr.type,
|
(_, resultOutParam) = getRetvalDeclarationForType(self.attr.type,
|
||||||
self.descriptor,
|
self.descriptor,
|
||||||
|
@ -3297,11 +3299,16 @@ class CGSpecializedGetter(CGAbstractExternMethod):
|
||||||
infallible = ('infallible' in
|
infallible = ('infallible' in
|
||||||
self.descriptor.getExtendedAttributes(self.attr,
|
self.descriptor.getExtendedAttributes(self.attr,
|
||||||
getter=True))
|
getter=True))
|
||||||
|
if name in self.descriptor.needsAbstract:
|
||||||
|
abstractName = re.sub(r'<\w+>', '', self.descriptor.nativeType)
|
||||||
|
extraPre = ' let abstract_this = %s::from_box(this);\n' % abstractName
|
||||||
|
argsPre = ['abstract_this']
|
||||||
if resultOutParam or self.attr.type.nullable() or not infallible:
|
if resultOutParam or self.attr.type.nullable() or not infallible:
|
||||||
nativeName = "Get" + nativeName
|
nativeName = "Get" + nativeName
|
||||||
return CGWrapper(CGIndenter(CGGetterCall(self.attr.type, nativeName,
|
return CGWrapper(CGIndenter(CGGetterCall(argsPre, self.attr.type, nativeName,
|
||||||
self.descriptor, self.attr)),
|
self.descriptor, self.attr)),
|
||||||
pre=" let obj = (*obj.unnamed);\n" +
|
pre=extraPre +
|
||||||
|
" let obj = (*obj.unnamed);\n" +
|
||||||
" let this = &mut (*this).payload;\n").define()
|
" let this = &mut (*this).payload;\n").define()
|
||||||
|
|
||||||
class CGGenericSetter(CGAbstractBindingMethod):
|
class CGGenericSetter(CGAbstractBindingMethod):
|
||||||
|
|
|
@ -2,9 +2,12 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use dom::bindings::utils::{DOMString, null_string, ErrorResult};
|
use dom::bindings::utils::{DOMString, str, null_string, ErrorResult};
|
||||||
use dom::htmlelement::HTMLElement;
|
use dom::htmlelement::HTMLElement;
|
||||||
|
use dom::node::{ScriptView, AbstractNode};
|
||||||
use extra::url::Url;
|
use extra::url::Url;
|
||||||
|
use layout_interface::{ContentBoxQuery, ContentBoxResponse};
|
||||||
|
use gfx::geometry::to_px;
|
||||||
|
|
||||||
pub struct HTMLImageElement {
|
pub struct HTMLImageElement {
|
||||||
parent: HTMLElement,
|
parent: HTMLElement,
|
||||||
|
@ -47,18 +50,74 @@ impl HTMLImageElement {
|
||||||
pub fn SetIsMap(&self, _is_map: bool, _rv: &mut ErrorResult) {
|
pub fn SetIsMap(&self, _is_map: bool, _rv: &mut ErrorResult) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn Width(&self) -> u32 {
|
pub fn Width(&self, abstract_self: AbstractNode<ScriptView>) -> u32 {
|
||||||
|
let node = &self.parent.parent.parent;
|
||||||
|
match node.owner_doc {
|
||||||
|
Some(doc) => {
|
||||||
|
match doc.with_base(|doc| doc.window) {
|
||||||
|
Some(win) => {
|
||||||
|
unsafe {
|
||||||
|
let page = win.page;
|
||||||
|
let (port, chan) = stream();
|
||||||
|
match (*page).query_layout(ContentBoxQuery(abstract_self, chan), port) {
|
||||||
|
ContentBoxResponse(rect) => {
|
||||||
|
to_px(rect.size.width) as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
debug!("no window");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn SetWidth(&mut self, _width: u32, _rv: &mut ErrorResult) {
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pub fn Height(&self) -> u32 {
|
None => {
|
||||||
|
debug!("no document");
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn SetHeight(&mut self, _height: u32, _rv: &mut ErrorResult) {
|
pub fn SetWidth(&mut self, width: u32, _rv: &mut ErrorResult) {
|
||||||
|
let node = &mut self.parent.parent;
|
||||||
|
node.set_attr(&str(~"width"),
|
||||||
|
&str(width.to_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn Height(&self, abstract_self: AbstractNode<ScriptView>) -> u32 {
|
||||||
|
let node = &self.parent.parent.parent;
|
||||||
|
match node.owner_doc {
|
||||||
|
Some(doc) => {
|
||||||
|
match doc.with_base(|doc| doc.window) {
|
||||||
|
Some(win) => {
|
||||||
|
unsafe {
|
||||||
|
let page = win.page;
|
||||||
|
let (port, chan) = stream();
|
||||||
|
match (*page).query_layout(ContentBoxQuery(abstract_self, chan), port) {
|
||||||
|
ContentBoxResponse(rect) => {
|
||||||
|
to_px(rect.size.height) as u32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
debug!("no window");
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
debug!("no document");
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn SetHeight(&mut self, height: u32, _rv: &mut ErrorResult) {
|
||||||
|
let node = &mut self.parent.parent;
|
||||||
|
node.set_attr(&str(~"height"),
|
||||||
|
&str(height.to_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn NaturalWidth(&self) -> u32 {
|
pub fn NaturalWidth(&self) -> u32 {
|
||||||
|
|
|
@ -9,7 +9,7 @@ use dom::document::AbstractDocument;
|
||||||
use dom::node::{AbstractNode, ScriptView};
|
use dom::node::{AbstractNode, ScriptView};
|
||||||
use dom::navigator::Navigator;
|
use dom::navigator::Navigator;
|
||||||
|
|
||||||
use layout_interface::ReflowForScriptQuery;
|
use layout_interface::ReflowForDisplay;
|
||||||
use script_task::{ExitMsg, FireTimerMsg, Page, ScriptChan};
|
use script_task::{ExitMsg, FireTimerMsg, Page, ScriptChan};
|
||||||
use servo_msg::compositor_msg::ScriptListener;
|
use servo_msg::compositor_msg::ScriptListener;
|
||||||
|
|
||||||
|
@ -168,7 +168,10 @@ impl Window {
|
||||||
|
|
||||||
pub fn content_changed(&self) {
|
pub fn content_changed(&self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*self.page).reflow_all(ReflowForScriptQuery, self.script_chan.clone(), self.compositor);
|
// FIXME This should probably be ReflowForQuery, not Display. All queries currently
|
||||||
|
// currently rely on the display list, which means we can't destroy it by
|
||||||
|
// doing a query reflow.
|
||||||
|
(*self.page).reflow_all(ReflowForDisplay, self.script_chan.clone(), self.compositor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
BIN
src/test/html/content/test.png
Normal file
BIN
src/test/html/content/test.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
10
src/test/html/content/test_img_width_height.html
Normal file
10
src/test/html/content/test_img_width_height.html
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title></title>
|
||||||
|
<script src="harness.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<img src="test.png"/>
|
||||||
|
<script src="test_img_width_height.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
21
src/test/html/content/test_img_width_height.js
Normal file
21
src/test/html/content/test_img_width_height.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// Testing get/set of image width/height properties
|
||||||
|
|
||||||
|
var img = window.document.getElementsByTagName("img")[0];
|
||||||
|
|
||||||
|
function wait_for_img_load(f) {
|
||||||
|
if (img.width != 0) {
|
||||||
|
f();
|
||||||
|
} else {
|
||||||
|
window.setTimeout(function() { wait_for_img_load(f) }, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wait_for_img_load(function() {
|
||||||
|
is(img.width, 500);
|
||||||
|
is(img.height, 378);
|
||||||
|
img.width = 200;
|
||||||
|
img.height = 100;
|
||||||
|
is(img.width, 200);
|
||||||
|
is(img.height, 100);
|
||||||
|
finish();
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue