зеркало из https://github.com/mozilla/gecko-dev.git
servo: Merge #6157 - Implement pattern fill style for canvas (from hyowon:canvas_pattern_fill); r=nox
Issue #6056 Depends on servo/rust-azure#160 Source-Repo: https://github.com/servo/servo Source-Revision: 9474e62d38f61f2b3a385ca32d64cab975b014ce
This commit is contained in:
Родитель
87cbc76930
Коммит
97b64f7e8d
|
@ -301,7 +301,22 @@ impl<'a> CanvasPaintTask<'a> {
|
|||
}
|
||||
|
||||
fn fill_rect(&self, rect: &Rect<f32>) {
|
||||
self.drawtarget.fill_rect(rect, self.state.fill_style.to_pattern_ref(),
|
||||
let draw_rect = Rect(rect.origin,
|
||||
match self.state.fill_style {
|
||||
Pattern::Surface(ref surface) => {
|
||||
let surface_size = surface.size();
|
||||
match (surface.repeat_x, surface.repeat_y) {
|
||||
(true, true) => rect.size,
|
||||
(true, false) => Size2D(rect.size.width, surface_size.height as f32),
|
||||
(false, true) => Size2D(surface_size.width as f32, rect.size.height),
|
||||
(false, false) => Size2D(surface_size.width as f32, surface_size.height as f32),
|
||||
}
|
||||
},
|
||||
_ => rect.size,
|
||||
}
|
||||
);
|
||||
|
||||
self.drawtarget.fill_rect(&draw_rect, self.state.fill_style.to_pattern_ref(),
|
||||
Some(&self.state.draw_options));
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ use azure::azure::{AzFloat, AzColor};
|
|||
use azure::azure_hl::{DrawTarget, Pattern, ColorPattern};
|
||||
use azure::azure_hl::{GradientStop, LinearGradientPattern, RadialGradientPattern, ExtendMode};
|
||||
use azure::azure_hl::{JoinStyle, CapStyle, CompositionOp};
|
||||
use azure::azure_hl::{SurfacePattern, SurfaceFormat};
|
||||
use cssparser::RGBA;
|
||||
use geom::matrix2d::Matrix2D;
|
||||
use geom::point::Point2D;
|
||||
|
@ -176,11 +177,33 @@ impl RadialGradientStyle {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SurfaceStyle {
|
||||
pub surface_data: Vec<u8>,
|
||||
pub surface_size: Size2D<i32>,
|
||||
pub repeat_x: bool,
|
||||
pub repeat_y: bool,
|
||||
}
|
||||
|
||||
impl SurfaceStyle {
|
||||
pub fn new(surface_data: Vec<u8>, surface_size: Size2D<i32>, repeat_x: bool, repeat_y: bool)
|
||||
-> SurfaceStyle {
|
||||
SurfaceStyle {
|
||||
surface_data: surface_data,
|
||||
surface_size: surface_size,
|
||||
repeat_x: repeat_x,
|
||||
repeat_y: repeat_y,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum FillOrStrokeStyle {
|
||||
Color(RGBA),
|
||||
LinearGradient(LinearGradientStyle),
|
||||
RadialGradient(RadialGradientStyle),
|
||||
Surface(SurfaceStyle),
|
||||
}
|
||||
|
||||
impl FillOrStrokeStyle {
|
||||
|
@ -220,6 +243,18 @@ impl FillOrStrokeStyle {
|
|||
radial_gradient_style.r0 as AzFloat, radial_gradient_style.r1 as AzFloat,
|
||||
drawtarget.create_gradient_stops(&gradient_stops, ExtendMode::Clamp),
|
||||
&Matrix2D::identity()))
|
||||
},
|
||||
FillOrStrokeStyle::Surface(ref surface_style) => {
|
||||
let source_surface = drawtarget.create_source_surface_from_data(
|
||||
&surface_style.surface_data,
|
||||
surface_style.surface_size,
|
||||
surface_style.surface_size.width * 4,
|
||||
SurfaceFormat::B8G8R8A8);
|
||||
|
||||
Pattern::Surface(SurfacePattern::new(
|
||||
source_surface.azure_source_surface,
|
||||
surface_style.repeat_x,
|
||||
surface_style.repeat_y))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -277,6 +312,26 @@ impl LineJoinStyle {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum RepetitionStyle {
|
||||
Repeat,
|
||||
RepeatX,
|
||||
RepeatY,
|
||||
NoRepeat,
|
||||
}
|
||||
|
||||
impl RepetitionStyle {
|
||||
pub fn from_str(string: &str) -> Option<RepetitionStyle> {
|
||||
match string {
|
||||
"repeat" => Some(RepetitionStyle::Repeat),
|
||||
"repeat-x" => Some(RepetitionStyle::RepeatX),
|
||||
"repeat-y" => Some(RepetitionStyle::RepeatY),
|
||||
"no-repeat" => Some(RepetitionStyle::NoRepeat),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum CompositionStyle {
|
||||
SrcIn,
|
||||
|
|
|
@ -35,11 +35,12 @@ use dom::bindings::utils::{Reflectable, Reflector, WindowProxyHandler};
|
|||
use script_task::ScriptChan;
|
||||
|
||||
use canvas_traits::{CanvasGradientStop, LinearGradientStyle, RadialGradientStyle};
|
||||
use canvas_traits::{LineCapStyle, LineJoinStyle, CompositionOrBlending};
|
||||
use canvas_traits::{LineCapStyle, LineJoinStyle, CompositionOrBlending, RepetitionStyle};
|
||||
use cssparser::RGBA;
|
||||
use encoding::types::EncodingRef;
|
||||
use geom::matrix2d::Matrix2D;
|
||||
use geom::rect::Rect;
|
||||
use geom::size::Size2D;
|
||||
use html5ever::tree_builder::QuirksMode;
|
||||
use hyper::header::Headers;
|
||||
use hyper::method::Method;
|
||||
|
@ -249,6 +250,7 @@ no_jsmanaged_fields!(isize, i8, i16, i32, i64);
|
|||
no_jsmanaged_fields!(Sender<T>);
|
||||
no_jsmanaged_fields!(Receiver<T>);
|
||||
no_jsmanaged_fields!(Rect<T>);
|
||||
no_jsmanaged_fields!(Size2D<T>);
|
||||
no_jsmanaged_fields!(Arc<T>);
|
||||
no_jsmanaged_fields!(Image, ImageCacheChan, ImageCacheTask, ScriptControlChan);
|
||||
no_jsmanaged_fields!(Atom, Namespace);
|
||||
|
@ -272,6 +274,7 @@ no_jsmanaged_fields!(Matrix2D<T>);
|
|||
no_jsmanaged_fields!(StorageType);
|
||||
no_jsmanaged_fields!(CanvasGradientStop, LinearGradientStyle, RadialGradientStyle);
|
||||
no_jsmanaged_fields!(LineCapStyle, LineJoinStyle, CompositionOrBlending);
|
||||
no_jsmanaged_fields!(RepetitionStyle);
|
||||
|
||||
impl JSTraceable for Box<ScriptChan+Send> {
|
||||
#[inline]
|
||||
|
|
|
@ -2,12 +2,54 @@
|
|||
* 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/. */
|
||||
|
||||
use dom::bindings::utils::Reflector;
|
||||
use canvas_traits::{FillOrStrokeStyle, SurfaceStyle, RepetitionStyle};
|
||||
use dom::bindings::codegen::Bindings::CanvasPatternBinding;
|
||||
use dom::bindings::global::GlobalRef;
|
||||
use dom::bindings::js::{JSRef, Temporary};
|
||||
use dom::bindings::utils::{Reflector, reflect_dom_object};
|
||||
use dom::canvasgradient::ToFillOrStrokeStyle;
|
||||
use geom::size::Size2D;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#canvaspattern
|
||||
#[dom_struct]
|
||||
pub struct CanvasPattern {
|
||||
reflector_: Reflector,
|
||||
surface_data: Vec<u8>,
|
||||
surface_size: Size2D<i32>,
|
||||
repeat_x: bool,
|
||||
repeat_y: bool,
|
||||
}
|
||||
|
||||
impl CanvasPattern {
|
||||
fn new_inherited(surface_data: Vec<u8>, surface_size: Size2D<i32>, repeat: RepetitionStyle) -> CanvasPattern {
|
||||
let (x, y) = match repeat {
|
||||
RepetitionStyle::Repeat => (true, true),
|
||||
RepetitionStyle::RepeatX => (true, false),
|
||||
RepetitionStyle::RepeatY => (false, true),
|
||||
RepetitionStyle::NoRepeat => (false, false),
|
||||
};
|
||||
|
||||
CanvasPattern {
|
||||
reflector_: Reflector::new(),
|
||||
surface_data: surface_data,
|
||||
surface_size: surface_size,
|
||||
repeat_x: x,
|
||||
repeat_y: y,
|
||||
}
|
||||
}
|
||||
pub fn new(global: GlobalRef,
|
||||
surface_data: Vec<u8>,
|
||||
surface_size: Size2D<i32>,
|
||||
repeat: RepetitionStyle)
|
||||
-> Temporary<CanvasPattern> {
|
||||
reflect_dom_object(box CanvasPattern::new_inherited(surface_data, surface_size, repeat),
|
||||
global, CanvasPatternBinding::Wrap)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToFillOrStrokeStyle for JSRef<'a, CanvasPattern> {
|
||||
fn to_fill_or_stroke_style(&self) -> FillOrStrokeStyle {
|
||||
FillOrStrokeStyle::Surface(
|
||||
SurfaceStyle::new(self.surface_data.clone(), self.surface_size, self.repeat_x, self.repeat_y))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,13 +9,14 @@ use dom::bindings::codegen::Bindings::ImageDataBinding::ImageDataMethods;
|
|||
use dom::bindings::codegen::InheritTypes::NodeCast;
|
||||
use dom::bindings::codegen::UnionTypes::HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D;
|
||||
use dom::bindings::codegen::UnionTypes::StringOrCanvasGradientOrCanvasPattern;
|
||||
use dom::bindings::error::Error::{IndexSize, NotSupported, Type, InvalidState};
|
||||
use dom::bindings::error::Error::{IndexSize, NotSupported, Type, InvalidState, Syntax};
|
||||
use dom::bindings::error::Fallible;
|
||||
use dom::bindings::global::{GlobalRef, GlobalField};
|
||||
use dom::bindings::js::{JS, JSRef, LayoutJS, Rootable, Temporary, Unrooted};
|
||||
use dom::bindings::num::Finite;
|
||||
use dom::bindings::utils::{Reflector, reflect_dom_object};
|
||||
use dom::canvasgradient::{CanvasGradient, CanvasGradientStyle, ToFillOrStrokeStyle};
|
||||
use dom::canvaspattern::CanvasPattern;
|
||||
use dom::htmlcanvaselement::{HTMLCanvasElement, HTMLCanvasElementHelpers};
|
||||
use dom::htmlimageelement::{HTMLImageElement, HTMLImageElementHelpers};
|
||||
use dom::imagedata::{ImageData, ImageDataHelpers};
|
||||
|
@ -29,7 +30,7 @@ use geom::rect::Rect;
|
|||
use geom::size::Size2D;
|
||||
|
||||
use canvas_traits::{CanvasMsg, Canvas2dMsg, CanvasCommonMsg};
|
||||
use canvas_traits::{FillOrStrokeStyle, LinearGradientStyle, RadialGradientStyle};
|
||||
use canvas_traits::{FillOrStrokeStyle, LinearGradientStyle, RadialGradientStyle, RepetitionStyle};
|
||||
use canvas_traits::{LineCapStyle, LineJoinStyle, CompositionOrBlending};
|
||||
use canvas::canvas_paint_task::CanvasPaintTask;
|
||||
|
||||
|
@ -865,7 +866,10 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
|||
Canvas2dMsg::SetFillStyle(gradient_root.r().to_fill_or_stroke_style()));
|
||||
self.renderer.send(msg).unwrap();
|
||||
}
|
||||
_ => {}
|
||||
StringOrCanvasGradientOrCanvasPattern::eCanvasPattern(pattern) => {
|
||||
self.renderer.send(CanvasMsg::Canvas2d(Canvas2dMsg::SetFillStyle(
|
||||
pattern.root().r().to_fill_or_stroke_style()))).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -997,6 +1001,44 @@ impl<'a> CanvasRenderingContext2DMethods for JSRef<'a, CanvasRenderingContext2D>
|
|||
RadialGradientStyle::new(x0, y0, r0, x1, y1, r1, Vec::new()))))
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-createpattern
|
||||
fn CreatePattern(self, image: HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D,
|
||||
repetition: DOMString) -> Fallible<Temporary<CanvasPattern>> {
|
||||
match image {
|
||||
HTMLImageElementOrHTMLCanvasElementOrCanvasRenderingContext2D::eHTMLImageElement(image) => {
|
||||
let image = image.root();
|
||||
let image_element = image.r();
|
||||
|
||||
let url = match image_element.get_url() {
|
||||
Some(url) => url,
|
||||
None => return Err(InvalidState),
|
||||
};
|
||||
|
||||
let img = match self.request_image_from_cache(url) {
|
||||
ImageResponse::Loaded(img) => img,
|
||||
ImageResponse::PlaceholderLoaded(_) | ImageResponse::None => return Err(InvalidState),
|
||||
};
|
||||
|
||||
let image_size = Size2D(img.width as f64, img.height as f64);
|
||||
let image_data = match img.pixels {
|
||||
PixelsByColorType::RGBA8(ref pixels) => pixels.to_vec(),
|
||||
PixelsByColorType::K8(_) => panic!("K8 color type not supported"),
|
||||
PixelsByColorType::RGB8(_) => panic!("RGB8 color type not supported"),
|
||||
PixelsByColorType::KA8(_) => panic!("KA8 color type not supported"),
|
||||
};
|
||||
|
||||
if let Some(rep) = RepetitionStyle::from_str(&repetition) {
|
||||
return Ok(CanvasPattern::new(self.global.root().r(),
|
||||
image_data,
|
||||
Size2D(image_size.width as i32, image_size.height as i32),
|
||||
rep));
|
||||
}
|
||||
return Err(Syntax);
|
||||
},
|
||||
_ => return Err(Type("Not implemented".to_owned())),
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/#dom-context-2d-linewidth
|
||||
fn LineWidth(self) -> f64 {
|
||||
let state = self.state.borrow();
|
||||
|
|
|
@ -62,7 +62,8 @@ interface CanvasRenderingContext2D {
|
|||
CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1);
|
||||
[Throws]
|
||||
CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1);
|
||||
//CanvasPattern createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetition);
|
||||
[Throws]
|
||||
CanvasPattern createPattern(CanvasImageSource image, [TreatNullAs=EmptyString] DOMString repetition);
|
||||
|
||||
// shadows
|
||||
attribute unrestricted double shadowOffsetX; // (default 0)
|
||||
|
|
Загрузка…
Ссылка в новой задаче