@@ -4183,6 +4183,8 @@ struct SurfaceAllocInfo {
4183
4183
// Only used for SVGFEGraph currently, this is the source pixels needed to
4184
4184
// render the pixels in clipped.
4185
4185
source : DeviceRect ,
4186
+ // Only used for SVGFEGraph, this is the same as clipped before rounding.
4187
+ clipped_notsnapped : DeviceRect ,
4186
4188
clipped_local : PictureRect ,
4187
4189
uv_rect_kind : UvRectKind ,
4188
4190
}
@@ -6378,6 +6380,14 @@ impl PicturePrimitive {
6378
6380
)
6379
6381
) ;
6380
6382
6383
+ // Determine the local space to device pixel scaling in the most robust
6384
+ // way, this accounts for local to device transform and
6385
+ // device_pixel_scale (if the task is shrunk in get_surface_rects).
6386
+ let subregion_to_device_scale_x = surface_rects. clipped_notsnapped . width ( ) / surface_rects. clipped_local . width ( ) ;
6387
+ let subregion_to_device_scale_y = surface_rects. clipped_notsnapped . height ( ) / surface_rects. clipped_local . height ( ) ;
6388
+ let subregion_to_device_offset_x = surface_rects. clipped_notsnapped . min . x - ( surface_rects. clipped_local . min . x * subregion_to_device_scale_x) . floor ( ) ;
6389
+ let subregion_to_device_offset_y = surface_rects. clipped_notsnapped . min . y - ( surface_rects. clipped_local . min . y * subregion_to_device_scale_y) . floor ( ) ;
6390
+
6381
6391
// Produce the target pixels, this is the result of the
6382
6392
// composite op
6383
6393
let filter_task_id = request_render_task (
@@ -6396,8 +6406,10 @@ impl PicturePrimitive {
6396
6406
source_subregion. cast_unit ( ) ,
6397
6407
target_subregion. cast_unit ( ) ,
6398
6408
prim_subregion. cast_unit ( ) ,
6399
- surface_rects. clipped . cast_unit ( ) ,
6400
- surface_rects. clipped_local . cast_unit ( ) ,
6409
+ subregion_to_device_scale_x,
6410
+ subregion_to_device_scale_y,
6411
+ subregion_to_device_offset_x,
6412
+ subregion_to_device_offset_y,
6401
6413
)
6402
6414
}
6403
6415
) ;
@@ -8050,7 +8062,11 @@ fn get_surface_rects(
8050
8062
}
8051
8063
} ;
8052
8064
8053
- let ( mut clipped, mut unclipped, mut source) = if surface. raster_spatial_node_index != surface. surface_spatial_node_index {
8065
+ // clipped_local is in LayoutPixel coordinates (technically if the parent
8066
+ // surface has a parent surface this would be PicturePixel), it needs to be
8067
+ // in WorldPixel before we can properly transform it into DevicePixel for
8068
+ // rasterizing.
8069
+ let ( clipped, unclipped, source) = if surface. raster_spatial_node_index != surface. surface_spatial_node_index {
8054
8070
assert_eq ! ( surface. device_pixel_scale. 0 , 1.0 ) ;
8055
8071
8056
8072
let local_to_world = SpaceMapper :: new_with_target (
@@ -8060,52 +8076,55 @@ fn get_surface_rects(
8060
8076
spatial_tree,
8061
8077
) ;
8062
8078
8063
- let clipped = ( local_to_world. map ( & clipped_local. cast_unit ( ) ) . unwrap ( ) * surface . device_pixel_scale ) . round_out ( ) ;
8064
- let unclipped = local_to_world. map ( & unclipped_local) . unwrap ( ) * surface . device_pixel_scale ;
8065
- let source = ( local_to_world. map ( & source_local. cast_unit ( ) ) . unwrap ( ) * surface . device_pixel_scale ) . round_out ( ) ;
8079
+ let clipped = local_to_world. map ( & clipped_local. cast_unit ( ) ) . unwrap ( ) ;
8080
+ let unclipped = local_to_world. map ( & unclipped_local) . unwrap ( ) ;
8081
+ let source = local_to_world. map ( & source_local. cast_unit ( ) ) . unwrap ( ) ;
8066
8082
8067
8083
( clipped, unclipped, source)
8068
8084
} else {
8069
- let clipped = ( clipped_local. cast_unit ( ) * surface . device_pixel_scale ) . round_out ( ) ;
8070
- let unclipped = unclipped_local. cast_unit ( ) * surface . device_pixel_scale ;
8071
- let source = ( source_local. cast_unit ( ) * surface . device_pixel_scale ) . round_out ( ) ;
8085
+ let clipped = clipped_local. cast_unit ( ) ;
8086
+ let unclipped = unclipped_local. cast_unit ( ) ;
8087
+ let source = source_local. cast_unit ( ) ;
8072
8088
8073
8089
( clipped, unclipped, source)
8074
8090
} ;
8075
8091
8076
8092
// Limit rendering extremely large pictures to something the hardware can
8077
8093
// handle, considering both clipped (target subregion) and source subregion.
8078
8094
//
8095
+ // Do this before we apply rounding because the scaling should not vary with
8096
+ // subpixel scrolling.
8097
+ //
8098
+ // Use slightly less than max_surface_size for subpixel rounding, and also
8099
+ // leave room for SVGFEGraph to add a 1 pixel inflate.
8100
+ //
8079
8101
// If you change this, test with:
8080
8102
// ./mach crashtest layout/svg/crashtests/387290-1.svg
8081
8103
let max_dimension =
8082
8104
clipped. width ( ) . max (
8083
8105
clipped. height ( ) . max (
8084
8106
source. width ( ) . max (
8085
8107
source. height ( )
8086
- ) ) ) . ceil ( ) ;
8087
- if max_dimension > max_surface_size {
8088
- let max_dimension =
8089
- clipped_local. width ( ) . max (
8090
- clipped_local. height ( ) . max (
8091
- source_local. width ( ) . max (
8092
- source_local. height ( )
8093
- ) ) ) . ceil ( ) ;
8108
+ ) ) ) * surface. device_pixel_scale . 0 ;
8109
+ let max_allowed_dimension = max_surface_size - 4.0 ;
8110
+ if max_allowed_dimension < max_dimension {
8094
8111
surface. raster_spatial_node_index = surface. surface_spatial_node_index ;
8095
- surface. device_pixel_scale = Scale :: new ( max_surface_size / max_dimension) ;
8112
+ surface. device_pixel_scale = Scale :: new ( surface . device_pixel_scale . 0 * max_allowed_dimension / max_dimension) ;
8096
8113
surface. local_scale = ( 1.0 , 1.0 ) ;
8097
-
8098
- clipped = ( clipped_local. cast_unit ( ) * surface. device_pixel_scale ) . round ( ) ;
8099
- unclipped = unclipped_local. cast_unit ( ) * surface. device_pixel_scale ;
8100
- source = ( source_local. cast_unit ( ) * surface. device_pixel_scale ) . round ( ) ;
8101
8114
}
8102
8115
8103
- let task_size = clipped. size ( ) . to_i32 ( ) ;
8116
+ // After deciding if downscaling is necessary, apply scaling and round.
8117
+ let clipped = clipped * surface. device_pixel_scale ;
8118
+ let unclipped = unclipped * surface. device_pixel_scale ;
8119
+ let source = ( source * surface. device_pixel_scale ) . round_out ( ) ;
8120
+ let clipped_snapped = clipped. round_out ( ) ;
8121
+
8122
+ let task_size = clipped_snapped. size ( ) . to_i32 ( ) ;
8104
8123
debug_assert ! ( task_size. width <= max_surface_size as i32 ) ;
8105
8124
debug_assert ! ( task_size. height <= max_surface_size as i32 ) ;
8106
8125
8107
8126
let uv_rect_kind = calculate_uv_rect_kind (
8108
- clipped ,
8127
+ clipped_snapped ,
8109
8128
unclipped,
8110
8129
) ;
8111
8130
@@ -8125,9 +8144,10 @@ fn get_surface_rects(
8125
8144
Some ( SurfaceAllocInfo {
8126
8145
task_size,
8127
8146
needs_scissor_rect,
8128
- clipped,
8147
+ clipped : clipped_snapped ,
8129
8148
unclipped,
8130
8149
source,
8150
+ clipped_notsnapped : clipped,
8131
8151
clipped_local,
8132
8152
uv_rect_kind,
8133
8153
} )
0 commit comments