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

[WIP] svg: support <circle> element #17681

Closed
wants to merge 10 commits into from
Prev

wip

  • Loading branch information
stshine committed Oct 6, 2017
commit c8a4f0a1a38639aa4b5dec43774379112a641199

Some generated files are not rendered by default. Learn more.

@@ -14,10 +14,10 @@ opt-level = 3
# debug = true
# lto = false

[patch.crates-io]
[replace]
"https://github.com/servo/webrender#webrender_api:0.50.0" = { path = "/home/stshine/Programs/webrender/webrender_api" }
"https://github.com/servo/webrender#webrender:0.50.0" = { path = "/home/stshine/Programs/webrender/webrender" }
# If you need to temporarily test Servo with a local fork of some upstream
# crate, add that here. Use the form:
#
# <crate> = { path = "/path/to/local/checkout" }
"webrender" = { path = '../webrender/webrender/' }
"webrender_api" = { path = '../webrender/webrender_api/' }
@@ -14,7 +14,6 @@ use app_units::{AU_PER_PX, Au};
use block::{BlockFlow, BlockStackingContextType};
use canvas_traits::canvas::{CanvasMsg, FromLayoutMsg};
use context::LayoutContext;
use core::f32::consts::PI;
use euclid::{Point2D, Rect, SideOffsets2D, Size2D, Transform3D, TypedSize2D};
use euclid::Vector2D;
use flex::FlexFlow;
@@ -47,6 +46,7 @@ use servo_url::ServoUrl;
use std::{cmp, f32};
use std::collections::HashMap;
use std::default::Default;
use std::f32::consts::PI;
use std::mem;
use std::sync::Arc;
use style::computed_values::{background_attachment, background_clip, background_origin};
@@ -63,7 +63,7 @@ use style::values::computed::{LengthOrPercentageOrAuto, NumberOrPercentage, Posi
use style::values::computed::effects::SimpleShadow;
// use style::values::computed::SVGPaint;
use style::values::computed::image::{EndingShape, LineDirection};
use style::values::generics::SVGPaintKind;
use style::values::generics::svg::SVGPaintKind;
use style::values::generics::background::BackgroundSize;
use style::values::generics::effects::Filter;
use style::values::generics::image::{Circle, Ellipse, EndingShape as GenericEndingShape};
@@ -3160,3 +3160,17 @@ impl Serialize for DebugId {
serializer.serialize_u16(self.0)
}
}


#[derive(Debug, Clone)]
pub enum SVGData {
SVG,
Circle
}

/// Represent an SVG element in layout.
#[derive(Debug, Clone)]
pub struct SVGItem {
pub data: SVGData,
pub style: ServoArc<ComputedValues>
}
@@ -585,10 +585,14 @@ impl ImageCache for ImageCacheImpl {
fn update_geometry(&self,
geometry_key: webrender_api::GeometryKey,
data: webrender_api::Geometry) {
self.store.lock().unwrap().webrender_api().update_geometry(geometry_key, data);
let mut updates = webrender_api::ResourceUpdates::new();
updates.update_geometry(geometry_key, data);
self.store.lock().unwrap().webrender_api().update_resources(updates);
}

fn delete_geometry(&self, key: webrender_api::GeometryKey) {
self.store.lock().unwrap().webrender_api().delete_geometry(key);
let mut updates = webrender_api::ResourceUpdates::new();
updates.delete_geometry(key);
self.store.lock().unwrap().webrender_api().update_resources(updates);
}
}
@@ -111,8 +111,6 @@ use time::Duration;
use uuid::Uuid;
use webrender_api::GeometryKey;
use webrender_api::ImageKey;
use webrender_api::{WebGLBufferId, WebGLError, WebGLFramebufferId, WebGLProgramId};
use webrender_api::{WebGLRenderbufferId, WebGLShaderId, WebGLTextureId, WebGLVertexArrayId};
use webvr_traits::WebVRGamepadHand;

/// A trait to allow tracing (only) DOM objects.
@@ -18,7 +18,7 @@ use style::properties::declaration_block::{Importance, PropertyDeclarationBlock}
use style::properties::{parse_one_declaration_into, SourcePropertyDeclaration};
use style::properties::PropertyId;
use style::shared_lock::Locked;
use style::stylearc::Arc;
use servo_arc::Arc;
use style_traits::PARSING_MODE_ALLOW_UNITLESS_LENGTH;

#[dom_struct]
@@ -60,7 +60,7 @@ impl SVGElement {
let quirks_mode = document.quirks_mode();
let url = win.get_url();

let id = PropertyId::parse(DOMString::from(&**attr.local_name()).into())
let id = PropertyId::parse(&attr.local_name(), None)
.expect("This SVG presentation attribute is not a css property!");
let mut declarations = SourcePropertyDeclaration::new();
let result = parse_one_declaration_into(&mut declarations,
@@ -79,6 +79,7 @@ pub struct PropertyDeclarationBlock {
declarations: Vec<PropertyDeclaration>,

/// The "important" flag for each declaration in `declarations`.
#[cfg_attr(feature = "servo", ignore_heap_size_of = "bitvec")]
declarations_importance: SmallBitVec,

longhands: LonghandIdSet,
@@ -333,6 +333,7 @@ impl From<Color> for RGBAColor {
/// Specified value for the "color" property, which resolves the `currentcolor`
/// keyword to the parent color instead of self's color.
#[derive(Clone, Debug, PartialEq, ToCss)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct ColorPropertyValue(pub Color);

impl ToComputedValue for ColorPropertyValue {
@@ -0,0 +1,154 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* 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 euclid::Size2D;
use fnv::FnvHasher;
use gleam::gl;
#[cfg(feature = "vector-rasterizer")]
use nanovg::{self, Color, Context, Solidity, Transform, Winding};
use std::collections::HashMap;
use std::hash::BuildHasherDefault;
use std::os::raw::c_int;
use std::sync::Arc;
use std::sync::mpsc::{Receiver, Sender, channel};
use std::thread;
use api::DeviceUintSize;
use api::{Command, GeometryKey, Geometry, GeometryItem};
use api::{ImageData, ImageDescriptor, ImageFormat};
use offscreen_gl_context::{ColorAttachmentType, GLContext, GLContextAttributes};
use offscreen_gl_context::NativeGLContext;

static VIEWPORT_WIDTH: i32 = 2048;
static VIEWPORT_HEIGHT: i32 = 2048;

pub enum GeometryRequestMsg {
Update(GeometryKey, Geometry),
Delete(GeometryKey),
Request(GeometryKey, DeviceUintSize),
EndFrame
}

pub enum GeometryResultMsg {
Image(GeometryKey, ImageData, ImageDescriptor),
EndFrame
}

#[cfg(feature = "vector-rasterizer")]
pub fn spawn_svg_renderer(device_pixel_ratio: f32)
-> (Sender<GeometryRequestMsg>, Receiver<GeometryResultMsg>) {
// Used for messages from resource cache -> geometry rendering thread.
let (msg_tx, msg_rx) = channel();
// Used for returning results from geometry rendering thread -> resource cache.
let (result_tx, result_rx) = channel();

thread::Builder::new()
.name("SvgThread".to_owned())
.spawn(move || {
let mut svg_geometries: HashMap<GeometryKey,
Geometry,
BuildHasherDefault<FnvHasher>> = HashMap::default();
let size = Size2D::new(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
let context_attributes = GLContextAttributes {
alpha: true,
depth: true,
stencil: true,
antialias: true,
premultiplied_alpha: true,
preserve_drawing_buffer: false
};
let context = GLContext::<NativeGLContext>::new(size,
context_attributes,
ColorAttachmentType::Texture,
gl::GlType::default(),
None).unwrap();
context.make_current().unwrap();
let vg = Context::create_gl2(nanovg::ANTIALIAS | nanovg::STENCIL_STROKES);

while let Ok(msg) = msg_rx.recv() {
match msg {
GeometryRequestMsg::Update(key, geometry) => {
svg_geometries.insert(key, geometry);
}
GeometryRequestMsg::Delete(key) => {
svg_geometries.remove(&key);
}
GeometryRequestMsg::Request(key, dimensions) => {
let geometry = svg_geometries.get(&key)
.expect("Requested geometry wasn't added!");
let image_data = paint_svg(&context,
&vg,
geometry,
dimensions,
device_pixel_ratio);
let data = ImageData::Raw(Arc::new(image_data));
let descriptor = ImageDescriptor {
format: ImageFormat::BGRA8,
width: dimensions.width,
height: dimensions.height,
stride: None,
offset: 0,
is_opaque: false,
};
let msg = GeometryResultMsg::Image(key, data, descriptor);
result_tx.send(msg).unwrap();
}
GeometryRequestMsg::EndFrame => {
result_tx.send(GeometryResultMsg::EndFrame).unwrap();
}
}
}
})
.expect("Thread spawning failed");
(msg_tx, result_rx)
}

fn paint_svg(context: &GLContext<NativeGLContext>,
vg: &Context,
geometry: &[GeometryItem],
dimensions: DeviceUintSize,
device_pixel_ratio: f32)
-> Vec<u8> {
context.gl().clear_color(0.0, 0.0, 0.0, 0.0);
context.gl().clear(gl::COLOR_BUFFER_BIT);

let canvas_width = (VIEWPORT_WIDTH as f32 / device_pixel_ratio) as u32;
let canvas_height = (VIEWPORT_HEIGHT as f32 / device_pixel_ratio) as u32;
vg.begin_frame(canvas_width, canvas_height, device_pixel_ratio);
// the opengl y-coordinate is inverse with svg, so apply a transform here first.
let transform = Transform::new(1.0, 0., 0., -1.0, 0., canvas_height as f32);
vg.transform(transform);
for item in geometry {
match item {
&GeometryItem::Shape(ref shape) => {
vg.begin_path();
for command in &shape.path {
match command {
&Command::MoveTo(point) => vg.move_to(point.x, point.y),
&Command::LineTo(point) => vg.line_to(point.x, point.y),
&Command::Arc(center, radius, start, end) => {
let direction = if start < end {
Winding::CCW
} else {
Winding::CW
};
vg.arc(center.x, center.y, radius, start, end, direction);
}
}
}
vg.close_path();
let color = Color::rgba(shape.fill.r, shape.fill.g, shape.fill.b, shape.fill.a);
vg.path_winding(Solidity::HOLE);
vg.fill_color(color);
vg.fill();
}
}
}
vg.end_frame();
context.gl().read_pixels(0,
0,
dimensions.width as c_int,
dimensions.height as c_int,
gl::BGRA,
gl::UNSIGNED_BYTE)
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.