tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

api_resources.rs (12725B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 use crate::api::{BlobImageKey, ImageDescriptor, DirtyRect, TileSize, DebugFlags};
      6 use crate::api::{BlobImageHandler, AsyncBlobImageRasterizer, BlobImageData, BlobImageParams};
      7 use crate::api::{BlobImageRequest, BlobImageDescriptor, FontTemplate};
      8 use crate::api::units::*;
      9 use glyph_rasterizer::{SharedFontResources, BaseFontInstance};
     10 use crate::render_api::{ResourceUpdate, TransactionMsg, AddFont};
     11 use crate::image_tiling::*;
     12 use crate::profiler;
     13 
     14 use std::collections::HashMap;
     15 use std::mem;
     16 use std::sync::Arc;
     17 
     18 /// We use this to generate the async blob rendering requests.
     19 struct BlobImageTemplate {
     20    descriptor: ImageDescriptor,
     21    tile_size: TileSize,
     22    dirty_rect: BlobDirtyRect,
     23    /// See ImageResource::visible_rect.
     24    visible_rect: DeviceIntRect,
     25    // If the active rect of the blob changes, this represents the
     26    // range of tiles that remain valid. This must be taken into
     27    // account in addition to the valid rect when submitting blob
     28    // rasterization requests.
     29    // `None` means the bounds have not changed (tiles are still valid).
     30    // `Some(TileRange::zero())` means all of the tiles are invalid.
     31    valid_tiles_after_bounds_change: Option<TileRange>,
     32 }
     33 
     34 pub struct ApiResources {
     35    blob_image_templates: HashMap<BlobImageKey, BlobImageTemplate>,
     36    pub blob_image_handler: Option<Box<dyn BlobImageHandler>>,
     37    fonts: SharedFontResources,
     38    // This should only be true for CI or debugging purposes. If true,
     39    // we'll restrict the size of blob images as a result effectively
     40    // rendering them incorrectly.
     41    debug_restrict_blob_size: bool,
     42 }
     43 
     44 impl ApiResources {
     45    pub fn new(
     46        blob_image_handler: Option<Box<dyn BlobImageHandler>>,
     47        fonts: SharedFontResources,
     48    ) -> Self {
     49        ApiResources {
     50            blob_image_templates: HashMap::new(),
     51            blob_image_handler,
     52            fonts,
     53            debug_restrict_blob_size: false,
     54        }
     55    }
     56 
     57    pub fn get_fonts(&self) -> SharedFontResources {
     58        self.fonts.clone()
     59    }
     60 
     61    pub fn set_debug_flags(&mut self, flags: DebugFlags) {
     62        self.debug_restrict_blob_size = flags.contains(DebugFlags::RESTRICT_BLOB_SIZE);
     63    }
     64 
     65    pub fn adjust_blob_visible_rect(&self, rect: &mut DeviceIntRect, size: Option<&mut DeviceIntSize>) {
     66        if self.debug_restrict_blob_size {
     67            rect.max.x = rect.max.x.min(rect.min.x + 2048);
     68            rect.max.y = rect.max.y.min(rect.min.y + 2048);
     69            if let Some(size) = size {
     70                size.width = size.width.min(2048);
     71                size.height = size.height.min(2048);
     72            }
     73        }
     74    }
     75 
     76    pub fn update(&mut self, transaction: &mut TransactionMsg) {
     77        let mut blobs_to_rasterize = Vec::new();
     78        for update in &mut transaction.resource_updates {
     79            match *update {
     80                ResourceUpdate::AddBlobImage(ref mut img) => {
     81                    self.adjust_blob_visible_rect(&mut img.visible_rect, Some(&mut img.descriptor.size));
     82                    self.blob_image_handler
     83                        .as_mut()
     84                        .expect("no blob image handler")
     85                        .add(img.key, Arc::clone(&img.data), &img.visible_rect, img.tile_size);
     86 
     87                    self.blob_image_templates.insert(
     88                        img.key,
     89                        BlobImageTemplate {
     90                            descriptor: img.descriptor,
     91                            tile_size: img.tile_size,
     92                            dirty_rect: DirtyRect::All,
     93                            valid_tiles_after_bounds_change: None,
     94                            visible_rect: img.visible_rect,
     95                        },
     96                    );
     97                    blobs_to_rasterize.push(img.key);
     98                }
     99                ResourceUpdate::UpdateBlobImage(ref mut img) => {
    100                    debug_assert_eq!(img.visible_rect.size(), img.descriptor.size);
    101                    self.adjust_blob_visible_rect(&mut img.visible_rect, Some(&mut img.descriptor.size));
    102                    self.update_blob_image(
    103                        img.key,
    104                        Some(&img.descriptor),
    105                        Some(&img.dirty_rect),
    106                        Some(Arc::clone(&img.data)),
    107                        &img.visible_rect,
    108                    );
    109                    blobs_to_rasterize.push(img.key);
    110                }
    111                ResourceUpdate::DeleteBlobImage(key) => {
    112                    transaction.use_scene_builder_thread = true;
    113                    self.blob_image_templates.remove(&key);
    114                    if let Some(ref mut handler) = self.blob_image_handler {
    115                        handler.delete(key);
    116                    }
    117                }
    118                ResourceUpdate::SetBlobImageVisibleArea(ref key, ref mut area) => {
    119                    self.adjust_blob_visible_rect(area, None);
    120                    self.update_blob_image(*key, None, None, None, &area);
    121                    blobs_to_rasterize.push(*key);
    122                }
    123                ResourceUpdate::AddFont(ref font) => {
    124                    let (key, template) = match font {
    125                        AddFont::Raw(key, bytes, index) => {
    126                            (key, FontTemplate::Raw(Arc::clone(bytes), *index))
    127                        }
    128                        AddFont::Native(key, native_font_handle) => {
    129                            (key, FontTemplate::Native(native_font_handle.clone()))
    130                        }
    131                    };
    132                    if let Some(shared_key) = self.fonts.font_keys.add_key(key, &template) {
    133                        self.fonts.templates.add_font(shared_key, template);
    134                    }
    135                }
    136                ResourceUpdate::AddFontInstance(ref mut instance) => {
    137                    let shared_font_key = self.fonts.font_keys.map_key(&instance.font_key);
    138                    assert!(self.fonts.templates.has_font(&shared_font_key));
    139                    // AddFontInstance will only be processed here, not in the resource cache, so it
    140                    // is safe to take the options rather than clone them.
    141                    let base = BaseFontInstance::new(
    142                        instance.key,
    143                        shared_font_key,
    144                        instance.glyph_size,
    145                        mem::take(&mut instance.options),
    146                        mem::take(&mut instance.platform_options),
    147                        mem::take(&mut instance.variations),
    148                    );
    149                    if let Some(shared_instance) = self.fonts.instance_keys.add_key(base) {
    150                        self.fonts.instances.add_font_instance(shared_instance);
    151                    }
    152                }
    153                ResourceUpdate::DeleteFont(_key) => {
    154                    transaction.use_scene_builder_thread = true;
    155                }
    156                ResourceUpdate::DeleteFontInstance(_key) => {
    157                    transaction.use_scene_builder_thread = true;
    158                    // We will delete from the shared font instance map in the resource cache
    159                    // after scene swap.
    160                }
    161                ResourceUpdate::DeleteImage(..) => {
    162                    transaction.use_scene_builder_thread = true;
    163                }
    164                _ => {}
    165            }
    166        }
    167 
    168        let (rasterizer, requests) = self.create_blob_scene_builder_requests(&blobs_to_rasterize);
    169        transaction.profile.set(profiler::RASTERIZED_BLOBS, blobs_to_rasterize.len());
    170        transaction.profile.set(profiler::RASTERIZED_BLOB_TILES, requests.len());
    171        transaction.use_scene_builder_thread |= !requests.is_empty();
    172        transaction.use_scene_builder_thread |= !transaction.scene_ops.is_empty();
    173        transaction.blob_rasterizer = rasterizer;
    174        transaction.blob_requests = requests;
    175    }
    176 
    177    pub fn enable_multithreading(&mut self, enable: bool) {
    178        if let Some(ref mut handler) = self.blob_image_handler {
    179            handler.enable_multithreading(enable);
    180        }
    181    }
    182 
    183    fn update_blob_image(
    184        &mut self,
    185        key: BlobImageKey,
    186        descriptor: Option<&ImageDescriptor>,
    187        dirty_rect: Option<&BlobDirtyRect>,
    188        data: Option<Arc<BlobImageData>>,
    189        visible_rect: &DeviceIntRect,
    190    ) {
    191        if let Some(data) = data {
    192            let dirty_rect = dirty_rect.expect("no dirty rect");
    193            self.blob_image_handler
    194                .as_mut()
    195                .expect("no blob image handler")
    196                .update(key, data, visible_rect, dirty_rect);
    197        }
    198 
    199        let image = self.blob_image_templates
    200            .get_mut(&key)
    201            .expect("Attempt to update non-existent blob image");
    202 
    203        let mut valid_tiles_after_bounds_change = compute_valid_tiles_if_bounds_change(
    204            &image.visible_rect,
    205            visible_rect,
    206            image.tile_size,
    207        );
    208 
    209        match (image.valid_tiles_after_bounds_change, valid_tiles_after_bounds_change) {
    210            (Some(old), Some(ref mut new)) => {
    211                *new = new.intersection(&old).unwrap_or_else(TileRange::zero);
    212            }
    213            (Some(old), None) => {
    214                valid_tiles_after_bounds_change = Some(old);
    215            }
    216            _ => {}
    217        }
    218 
    219        let blob_size = visible_rect.size();
    220 
    221        if let Some(descriptor) = descriptor {
    222            image.descriptor = *descriptor;
    223        } else {
    224            // make sure the descriptor size matches the visible rect.
    225            // This might not be necessary but let's stay on the safe side.
    226            image.descriptor.size = blob_size;
    227        }
    228 
    229        if let Some(dirty_rect) = dirty_rect {
    230            image.dirty_rect = image.dirty_rect.union(dirty_rect);
    231        }
    232 
    233        image.valid_tiles_after_bounds_change = valid_tiles_after_bounds_change;
    234        image.visible_rect = *visible_rect;
    235    }
    236 
    237    pub fn create_blob_scene_builder_requests(
    238        &mut self,
    239        keys: &[BlobImageKey]
    240    ) -> (Option<Box<dyn AsyncBlobImageRasterizer>>, Vec<BlobImageParams>) {
    241        if self.blob_image_handler.is_none() || keys.is_empty() {
    242            return (None, Vec::new());
    243        }
    244 
    245        let mut blob_request_params = Vec::new();
    246        for key in keys {
    247            let template = self.blob_image_templates.get_mut(key)
    248                .expect("no blob image template");
    249 
    250            // If we know that only a portion of the blob image is in the viewport,
    251            // only request these visible tiles since blob images can be huge.
    252            let tiles = compute_tile_range(
    253                &template.visible_rect,
    254                template.tile_size,
    255            );
    256 
    257            // Don't request tiles that weren't invalidated.
    258            let dirty_tiles = match template.dirty_rect {
    259                DirtyRect::Partial(dirty_rect) => {
    260                    compute_tile_range(
    261                        &dirty_rect.cast_unit(),
    262                        template.tile_size,
    263                    )
    264                }
    265                DirtyRect::All => tiles,
    266            };
    267 
    268            for_each_tile_in_range(&tiles, |tile| {
    269                let still_valid = template.valid_tiles_after_bounds_change
    270                    .map(|valid_tiles| valid_tiles.contains(tile))
    271                    .unwrap_or(true);
    272 
    273                if still_valid && !dirty_tiles.contains(tile) {
    274                    return;
    275                }
    276 
    277                let descriptor = BlobImageDescriptor {
    278                    rect: compute_tile_rect(
    279                        &template.visible_rect,
    280                        template.tile_size,
    281                        tile,
    282                    ).cast_unit(),
    283                    format: template.descriptor.format,
    284                };
    285 
    286                assert!(descriptor.rect.width() > 0 && descriptor.rect.height() > 0);
    287                blob_request_params.push(
    288                    BlobImageParams {
    289                        request: BlobImageRequest { key: *key, tile },
    290                        descriptor,
    291                        dirty_rect: DirtyRect::All,
    292                    }
    293                );
    294            });
    295 
    296            template.dirty_rect = DirtyRect::empty();
    297            template.valid_tiles_after_bounds_change = None;
    298        }
    299 
    300        let handler = self.blob_image_handler.as_mut()
    301            .expect("no blob image handler");
    302        handler.prepare_resources(&self.fonts, &blob_request_params);
    303        (Some(handler.create_blob_rasterizer()), blob_request_params)
    304    }
    305 }