mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
The Linux kernel imposes a 15-byte limit on thread names[1]. This means information that does not fit in this limit, e.g., the pipeline ID of layout and script threads, is lost in a debugger and profiler (see the first column of the table below). This commit shortens the thread names used in Servo to maximize the amount of information conveyed. It also rectifies some inconsistencies in the names. | Before | After | |-------------------|-------------------| | `BluetoothThread` | `Bluetooth` | | `CanvasThread` | `Canvas` | | `display alert d` | `AlertDialog` | | `FontCacheThread` | `FontCache` | | `GLPlayerThread` | `GLPlayer` | | `HTML Parser` | `Parse:www.examp` | | `LayoutThread Pi` | `Layout(1,1)` | | `Memory profiler` | `MemoryProfiler` | | `Memory profiler` | `MemoryProfTimer` | | `OfflineAudioCon` | `OfflineACResolv` | | `PullTimelineMar` | `PullTimelineDat` | | `ScriptThread Pi` | `Script(1,1)` | | `WebWorker for h` | `WW:www.example.` | | `ServiceWorker f` | `SW:www.example.` | | `ServiceWorkerMa` | `SvcWorkerManage` | | `Time profiler t` | `TimeProfTimer` | | `Time profiler` | `TimeProfiler` | | `WebGL thread` | `WebGL` | | `Choose a device` | `DevicePicker` | | `Pick a file` | `FilePicker` | | `Pick files` | `FilePicker` | [1]: https://stackoverflow.com/questions/5026531/thread-name-longer-than-15-chars
273 lines
12 KiB
Rust
273 lines
12 KiB
Rust
/* 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 https://mozilla.org/MPL/2.0/. */
|
|
|
|
use crate::canvas_data::*;
|
|
use canvas_traits::canvas::*;
|
|
use canvas_traits::ConstellationCanvasMsg;
|
|
use crossbeam_channel::{select, unbounded, Sender};
|
|
use euclid::default::Size2D;
|
|
use gfx::font_cache_thread::FontCacheThread;
|
|
use ipc_channel::ipc::{self, IpcSender};
|
|
use ipc_channel::router::ROUTER;
|
|
use std::borrow::ToOwned;
|
|
use std::collections::HashMap;
|
|
use std::thread;
|
|
use webrender_api::{ImageData, ImageDescriptor, ImageKey};
|
|
|
|
pub enum AntialiasMode {
|
|
Default,
|
|
None,
|
|
}
|
|
|
|
pub enum ImageUpdate {
|
|
Add(ImageKey, ImageDescriptor, ImageData),
|
|
Update(ImageKey, ImageDescriptor, ImageData),
|
|
Delete(ImageKey),
|
|
}
|
|
|
|
pub trait WebrenderApi {
|
|
fn generate_key(&self) -> Result<webrender_api::ImageKey, ()>;
|
|
fn update_images(&self, updates: Vec<ImageUpdate>);
|
|
fn clone(&self) -> Box<dyn WebrenderApi>;
|
|
}
|
|
|
|
pub struct CanvasPaintThread<'a> {
|
|
canvases: HashMap<CanvasId, CanvasData<'a>>,
|
|
next_canvas_id: CanvasId,
|
|
webrender_api: Box<dyn WebrenderApi>,
|
|
font_cache_thread: FontCacheThread,
|
|
}
|
|
|
|
impl<'a> CanvasPaintThread<'a> {
|
|
fn new(
|
|
webrender_api: Box<dyn WebrenderApi>,
|
|
font_cache_thread: FontCacheThread,
|
|
) -> CanvasPaintThread<'a> {
|
|
CanvasPaintThread {
|
|
canvases: HashMap::new(),
|
|
next_canvas_id: CanvasId(0),
|
|
webrender_api,
|
|
font_cache_thread,
|
|
}
|
|
}
|
|
|
|
/// Creates a new `CanvasPaintThread` and returns an `IpcSender` to
|
|
/// communicate with it.
|
|
pub fn start(
|
|
webrender_api: Box<dyn WebrenderApi + Send>,
|
|
font_cache_thread: FontCacheThread,
|
|
) -> (Sender<ConstellationCanvasMsg>, IpcSender<CanvasMsg>) {
|
|
let (ipc_sender, ipc_receiver) = ipc::channel::<CanvasMsg>().unwrap();
|
|
let msg_receiver = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(ipc_receiver);
|
|
let (create_sender, create_receiver) = unbounded();
|
|
thread::Builder::new()
|
|
.name("Canvas".to_owned())
|
|
.spawn(move || {
|
|
let mut canvas_paint_thread = CanvasPaintThread::new(webrender_api, font_cache_thread);
|
|
loop {
|
|
select! {
|
|
recv(msg_receiver) -> msg => {
|
|
match msg {
|
|
Ok(CanvasMsg::Canvas2d(message, canvas_id)) => {
|
|
canvas_paint_thread.process_canvas_2d_message(message, canvas_id);
|
|
},
|
|
Ok(CanvasMsg::Close(canvas_id)) => {
|
|
canvas_paint_thread.canvases.remove(&canvas_id);
|
|
},
|
|
Ok(CanvasMsg::Recreate(size, canvas_id)) => {
|
|
canvas_paint_thread.canvas(canvas_id).recreate(size);
|
|
},
|
|
Ok(CanvasMsg::FromScript(message, canvas_id)) => match message {
|
|
FromScriptMsg::SendPixels(chan) => {
|
|
canvas_paint_thread.canvas(canvas_id).send_pixels(chan);
|
|
},
|
|
},
|
|
Ok(CanvasMsg::FromLayout(message, canvas_id)) => match message {
|
|
FromLayoutMsg::SendData(chan) => {
|
|
canvas_paint_thread.canvas(canvas_id).send_data(chan);
|
|
},
|
|
},
|
|
Err(e) => {
|
|
warn!("Error on CanvasPaintThread receive ({})", e);
|
|
},
|
|
}
|
|
}
|
|
recv(create_receiver) -> msg => {
|
|
match msg {
|
|
Ok(ConstellationCanvasMsg::Create {
|
|
id_sender: creator,
|
|
size,
|
|
antialias
|
|
}) => {
|
|
let canvas_id = canvas_paint_thread.create_canvas(size, antialias);
|
|
creator.send(canvas_id).unwrap();
|
|
},
|
|
Ok(ConstellationCanvasMsg::Exit) => break,
|
|
Err(e) => {
|
|
warn!("Error on CanvasPaintThread receive ({})", e);
|
|
break;
|
|
},
|
|
}
|
|
}
|
|
}
|
|
}
|
|
})
|
|
.expect("Thread spawning failed");
|
|
|
|
(create_sender, ipc_sender)
|
|
}
|
|
|
|
pub fn create_canvas(&mut self, size: Size2D<u64>, antialias: bool) -> CanvasId {
|
|
let antialias = if antialias {
|
|
AntialiasMode::Default
|
|
} else {
|
|
AntialiasMode::None
|
|
};
|
|
|
|
let font_cache_thread = self.font_cache_thread.clone();
|
|
|
|
let canvas_id = self.next_canvas_id.clone();
|
|
self.next_canvas_id.0 += 1;
|
|
|
|
let canvas_data = CanvasData::new(
|
|
size,
|
|
self.webrender_api.clone(),
|
|
antialias,
|
|
font_cache_thread,
|
|
);
|
|
self.canvases.insert(canvas_id.clone(), canvas_data);
|
|
|
|
canvas_id
|
|
}
|
|
|
|
fn process_canvas_2d_message(&mut self, message: Canvas2dMsg, canvas_id: CanvasId) {
|
|
match message {
|
|
Canvas2dMsg::FillText(text, x, y, max_width, style, is_rtl) => {
|
|
self.canvas(canvas_id).set_fill_style(style);
|
|
self.canvas(canvas_id)
|
|
.fill_text(text, x, y, max_width, is_rtl);
|
|
},
|
|
Canvas2dMsg::FillRect(rect, style) => {
|
|
self.canvas(canvas_id).set_fill_style(style);
|
|
self.canvas(canvas_id).fill_rect(&rect);
|
|
},
|
|
Canvas2dMsg::StrokeRect(rect, style) => {
|
|
self.canvas(canvas_id).set_stroke_style(style);
|
|
self.canvas(canvas_id).stroke_rect(&rect);
|
|
},
|
|
Canvas2dMsg::ClearRect(ref rect) => self.canvas(canvas_id).clear_rect(rect),
|
|
Canvas2dMsg::BeginPath => self.canvas(canvas_id).begin_path(),
|
|
Canvas2dMsg::ClosePath => self.canvas(canvas_id).close_path(),
|
|
Canvas2dMsg::Fill(style) => {
|
|
self.canvas(canvas_id).set_fill_style(style);
|
|
self.canvas(canvas_id).fill();
|
|
},
|
|
Canvas2dMsg::Stroke(style) => {
|
|
self.canvas(canvas_id).set_stroke_style(style);
|
|
self.canvas(canvas_id).stroke();
|
|
},
|
|
Canvas2dMsg::Clip => self.canvas(canvas_id).clip(),
|
|
Canvas2dMsg::IsPointInPath(x, y, fill_rule, chan) => self
|
|
.canvas(canvas_id)
|
|
.is_point_in_path(x, y, fill_rule, chan),
|
|
Canvas2dMsg::DrawImage(
|
|
imagedata,
|
|
image_size,
|
|
dest_rect,
|
|
source_rect,
|
|
smoothing_enabled,
|
|
) => {
|
|
let data = imagedata.map_or_else(
|
|
|| vec![0; image_size.width as usize * image_size.height as usize * 4],
|
|
|bytes| bytes.into_vec(),
|
|
);
|
|
self.canvas(canvas_id).draw_image(
|
|
data,
|
|
image_size,
|
|
dest_rect,
|
|
source_rect,
|
|
smoothing_enabled,
|
|
)
|
|
},
|
|
Canvas2dMsg::DrawImageInOther(
|
|
other_canvas_id,
|
|
image_size,
|
|
dest_rect,
|
|
source_rect,
|
|
smoothing,
|
|
) => {
|
|
let image_data = self
|
|
.canvas(canvas_id)
|
|
.read_pixels(source_rect.to_u64(), image_size.to_u64());
|
|
self.canvas(other_canvas_id).draw_image(
|
|
image_data.into(),
|
|
source_rect.size,
|
|
dest_rect,
|
|
source_rect,
|
|
smoothing,
|
|
);
|
|
},
|
|
Canvas2dMsg::MoveTo(ref point) => self.canvas(canvas_id).move_to(point),
|
|
Canvas2dMsg::LineTo(ref point) => self.canvas(canvas_id).line_to(point),
|
|
Canvas2dMsg::Rect(ref rect) => self.canvas(canvas_id).rect(rect),
|
|
Canvas2dMsg::QuadraticCurveTo(ref cp, ref pt) => {
|
|
self.canvas(canvas_id).quadratic_curve_to(cp, pt)
|
|
},
|
|
Canvas2dMsg::BezierCurveTo(ref cp1, ref cp2, ref pt) => {
|
|
self.canvas(canvas_id).bezier_curve_to(cp1, cp2, pt)
|
|
},
|
|
Canvas2dMsg::Arc(ref center, radius, start, end, ccw) => {
|
|
self.canvas(canvas_id).arc(center, radius, start, end, ccw)
|
|
},
|
|
Canvas2dMsg::ArcTo(ref cp1, ref cp2, radius) => {
|
|
self.canvas(canvas_id).arc_to(cp1, cp2, radius)
|
|
},
|
|
Canvas2dMsg::Ellipse(ref center, radius_x, radius_y, rotation, start, end, ccw) => self
|
|
.canvas(canvas_id)
|
|
.ellipse(center, radius_x, radius_y, rotation, start, end, ccw),
|
|
Canvas2dMsg::RestoreContext => self.canvas(canvas_id).restore_context_state(),
|
|
Canvas2dMsg::SaveContext => self.canvas(canvas_id).save_context_state(),
|
|
Canvas2dMsg::SetLineWidth(width) => self.canvas(canvas_id).set_line_width(width),
|
|
Canvas2dMsg::SetLineCap(cap) => self.canvas(canvas_id).set_line_cap(cap),
|
|
Canvas2dMsg::SetLineJoin(join) => self.canvas(canvas_id).set_line_join(join),
|
|
Canvas2dMsg::SetMiterLimit(limit) => self.canvas(canvas_id).set_miter_limit(limit),
|
|
Canvas2dMsg::GetTransform(sender) => {
|
|
let transform = self.canvas(canvas_id).get_transform();
|
|
sender.send(transform).unwrap();
|
|
},
|
|
Canvas2dMsg::SetTransform(ref matrix) => self.canvas(canvas_id).set_transform(matrix),
|
|
Canvas2dMsg::SetGlobalAlpha(alpha) => self.canvas(canvas_id).set_global_alpha(alpha),
|
|
Canvas2dMsg::SetGlobalComposition(op) => {
|
|
self.canvas(canvas_id).set_global_composition(op)
|
|
},
|
|
Canvas2dMsg::GetImageData(dest_rect, canvas_size, sender) => {
|
|
let pixels = self.canvas(canvas_id).read_pixels(dest_rect, canvas_size);
|
|
sender.send(&pixels).unwrap();
|
|
},
|
|
Canvas2dMsg::PutImageData(rect, receiver) => {
|
|
self.canvas(canvas_id)
|
|
.put_image_data(receiver.recv().unwrap(), rect);
|
|
},
|
|
Canvas2dMsg::SetShadowOffsetX(value) => {
|
|
self.canvas(canvas_id).set_shadow_offset_x(value)
|
|
},
|
|
Canvas2dMsg::SetShadowOffsetY(value) => {
|
|
self.canvas(canvas_id).set_shadow_offset_y(value)
|
|
},
|
|
Canvas2dMsg::SetShadowBlur(value) => self.canvas(canvas_id).set_shadow_blur(value),
|
|
Canvas2dMsg::SetShadowColor(color) => self.canvas(canvas_id).set_shadow_color(color),
|
|
Canvas2dMsg::SetFont(font_style) => self.canvas(canvas_id).set_font(font_style),
|
|
Canvas2dMsg::SetTextAlign(text_align) => {
|
|
self.canvas(canvas_id).set_text_align(text_align)
|
|
},
|
|
Canvas2dMsg::SetTextBaseline(text_baseline) => {
|
|
self.canvas(canvas_id).set_text_baseline(text_baseline)
|
|
},
|
|
}
|
|
}
|
|
|
|
fn canvas(&mut self, canvas_id: CanvasId) -> &mut CanvasData<'a> {
|
|
self.canvases.get_mut(&canvas_id).expect("Bogus canvas id")
|
|
}
|
|
}
|