Import cobalt 25.master.0.1034729
diff --git a/ui/gfx/BUILD.gn b/ui/gfx/BUILD.gn
index 4d34a46..dae0d15 100644
--- a/ui/gfx/BUILD.gn
+++ b/ui/gfx/BUILD.gn
@@ -1,13 +1,17 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/features.gni")
import("//build/config/ozone.gni")
import("//build/config/ui.gni")
-import("//device/vr/buildflags/buildflags.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
import("//testing/test.gni")
+if (is_ios) {
+ import("//build/config/ios/bundle_data_from_filelist.gni")
+}
+
if (is_android) {
import("//build/config/android/config.gni")
import("//build/config/android/rules.gni")
@@ -21,446 +25,32 @@
sources = [ "gfx_export.h" ]
}
-# Used for color generation at build time without importing all the gfx.
-component("color_utils") {
- sources = [
- "color_palette.h",
- "color_utils.cc",
- "color_utils.h",
- ]
- defines = [ "GFX_IMPLEMENTATION" ]
- public_deps = [
- ":gfx_export",
- "//base",
- "//skia",
- "//ui/gfx/geometry",
- ]
-}
-
-component("gfx_skia") {
- sources = [
- "gfx_skia_export.h",
- "skia_util.cc",
- "skia_util.h",
- ]
- configs += [ "//build/config/compiler:wexit_time_destructors" ]
- public_deps = [
- "//base",
- "//skia",
- ]
- defines = [ "GFX_SKIA_IMPLEMENTATION" ]
-}
-
component("gfx") {
- sources = [
- "break_list.h",
- "color_analysis.cc",
- "color_analysis.h",
- "color_transform.cc",
- "color_transform.h",
- "decorated_text.cc",
- "decorated_text.h",
- "delegated_ink_metadata.cc",
- "delegated_ink_metadata.h",
- "delegated_ink_point.cc",
- "delegated_ink_point.h",
- "extension_set.cc",
- "extension_set.h",
- "favicon_size.cc",
- "favicon_size.h",
- "font.cc",
- "font.h",
- "font_fallback.h",
- "font_list.cc",
- "font_list.h",
- "font_list_impl.cc",
- "font_list_impl.h",
- "font_render_params.cc",
- "font_render_params.h",
- "font_util.cc",
- "font_util.h",
- "gdi_util.cc",
- "gdi_util.h",
- "gpu_extra_info.cc",
- "gpu_extra_info.h",
- "half_float.cc",
- "half_float.h",
- "icon_util.cc",
- "icon_util.h",
- "image/buffer_w_stream.cc",
- "image/buffer_w_stream.h",
- "image/image.cc",
- "image/image.h",
- "image/image_family.cc",
- "image/image_family.h",
- "image/image_platform.h",
- "image/image_png_rep.cc",
- "image/image_png_rep.h",
- "image/image_skia.cc",
- "image/image_skia.h",
- "image/image_skia_rep.h",
- "image/image_skia_source.cc",
- "image/image_skia_source.h",
- "image/image_util.cc",
- "image/image_util.h",
- "interpolated_transform.cc",
- "interpolated_transform.h",
- "nine_image_painter.cc",
- "nine_image_painter.h",
- "overlay_plane_data.cc",
- "overlay_plane_data.h",
- "overlay_transform_utils.cc",
- "overlay_transform_utils.h",
- "platform_font.h",
- "rendering_pipeline.cc",
- "rendering_pipeline.h",
- "rendering_stage_scheduler.cc",
- "rendering_stage_scheduler.h",
- "scrollbar_size.cc",
- "scrollbar_size.h",
- "selection_model.cc",
- "selection_model.h",
- "sequential_id_generator.cc",
- "sequential_id_generator.h",
- "shadow_value.cc",
- "shadow_value.h",
- "skbitmap_operations.cc",
- "skbitmap_operations.h",
- "swap_result.cc",
- "sys_color_change_listener.cc",
- "sys_color_change_listener.h",
- "text_constants.h",
- "text_elider.cc",
- "text_elider.h",
- "text_utils.cc",
- "text_utils.h",
- "ui_gfx_exports.cc",
- "utf16_indexing.cc",
- "utf16_indexing.h",
- "vector_icon_types.h",
- "vector_icon_utils.cc",
- "vector_icon_utils.h",
- "video_types.h",
- "vsync_provider.cc",
- "vsync_provider.h",
- ]
- if (is_android) {
- sources += [
- "android/android_surface_control_compat.cc",
- "android/android_surface_control_compat.h",
- "android/java_bitmap.cc",
- "android/java_bitmap.h",
- "android/view_configuration.cc",
- "android/view_configuration.h",
- ]
- }
- if (is_linux || is_chromeos) {
- sources += [
- "font_fallback_linux.cc",
- "font_fallback_linux.h",
- "font_render_params_linux.cc",
- "linux/fontconfig_util.cc",
- "linux/fontconfig_util.h",
- ]
- }
- if (is_mac) {
- sources += [
- "canvas_paint_mac.h",
- "canvas_paint_mac.mm",
- "decorated_text_mac.h",
- "decorated_text_mac.mm",
- "font_fallback_mac.mm",
- "font_render_params_mac.cc",
- "image/image_mac.mm",
- "image/image_skia_util_mac.h",
- "image/image_skia_util_mac.mm",
- "image/image_util_mac.mm",
- "mac/coordinate_conversion.h",
- "mac/coordinate_conversion.mm",
- "mac/nswindow_frame_controls.h",
- "mac/nswindow_frame_controls.mm",
- "mac/scoped_cocoa_disable_screen_updates.h",
- "mac/scoped_cocoa_disable_screen_updates.mm",
- "path_mac.h",
- "path_mac.mm",
- "platform_font_mac.h",
- "platform_font_mac.mm",
- "scoped_cg_context_save_gstate_mac.h",
- "scoped_ns_graphics_context_save_gstate_mac.h",
- "scoped_ns_graphics_context_save_gstate_mac.mm",
- ]
- }
- if (is_win) {
- sources += [
- "font_fallback_win.cc",
- "font_fallback_win.h",
- "font_render_params_win.cc",
- "path_win.cc",
- "path_win.h",
- "system_fonts_win.cc",
- "system_fonts_win.h",
- "win/crash_id_helper.cc",
- "win/crash_id_helper.h",
- "win/direct_write.cc",
- "win/direct_write.h",
- "win/hwnd_util.cc",
- "win/hwnd_util.h",
- "win/msg_util.h",
- "win/physical_size.cc",
- "win/physical_size.h",
- "win/rendering_window_manager.cc",
- "win/rendering_window_manager.h",
- "win/scoped_set_map_mode.h",
- "win/singleton_hwnd.cc",
- "win/singleton_hwnd.h",
- "win/singleton_hwnd_hot_key_observer.cc",
- "win/singleton_hwnd_hot_key_observer.h",
- "win/singleton_hwnd_observer.cc",
- "win/singleton_hwnd_observer.h",
- "win/text_analysis_source.cc",
- "win/text_analysis_source.h",
- "win/window_impl.cc",
- "win/window_impl.h",
- ]
- }
- if (is_ios) {
- sources += [
- "image/image_ios.mm",
- "image/image_skia_rep_ios.cc",
- "image/image_skia_rep_ios.h",
- "image/image_skia_util_ios.h",
- "image/image_skia_util_ios.mm",
- "image/image_util_ios.mm",
- "ios/NSString+CrStringDrawing.h",
- "ios/NSString+CrStringDrawing.mm",
- "ios/uikit_util.h",
- "ios/uikit_util.mm",
- "platform_font_ios.h",
- "platform_font_ios.mm",
- "scoped_ui_graphics_push_context_ios.h",
- "scoped_ui_graphics_push_context_ios.mm",
- "text_utils_ios.mm",
- ]
- }
- if (!is_ios) {
- sources += [
- "blit.cc",
- "blit.h",
- "canvas.cc",
- "canvas.h",
- "canvas_skia.cc",
- "canvas_skia_paint.h",
- "image/canvas_image_source.cc",
- "image/canvas_image_source.h",
- "image/image_generic.cc",
- "image/image_skia_operations.cc",
- "image/image_skia_operations.h",
- "image/image_skia_rep_default.cc",
- "image/image_skia_rep_default.h",
- "paint_throbber.cc",
- "paint_throbber.h",
- "scoped_canvas.cc",
- "scoped_canvas.h",
- "shadow_util.cc",
- "shadow_util.h",
- "skia_paint_util.cc",
- "skia_paint_util.h",
- ]
- }
-
- configs += [
- "//build/config:precompiled_headers",
- "//build/config/compiler:noshadowing",
- "//build/config/compiler:wexit_time_destructors",
- ]
-
# This is part of the gfx component in the component build.
defines = [ "GFX_IMPLEMENTATION" ]
public_deps = [
":color_space",
- ":color_utils",
- ":gfx_skia",
- ":gfx_switches",
- ":memory_buffer_sources",
- ":native_widget_types",
- ":resize_image_dimensions",
- ":selection_bound_sources",
- "//base",
- "//skia",
- "//skia:skcms",
- "//third_party/icu",
- "//ui/gfx/animation",
- "//ui/gfx/codec",
"//ui/gfx/geometry",
- "//ui/gfx/geometry:geometry_skia",
- "//ui/gfx/range",
]
- deps = [
- ":gfx_export",
- "//base",
- "//base:base_static",
- "//base:i18n",
- "//base/third_party/dynamic_annotations",
- "//build:chromeos_buildflags",
- "//device/vr/buildflags",
- "//mojo/public/cpp/bindings:struct_traits",
- "//skia",
- "//third_party/zlib",
- ]
-
- if (!is_apple) {
- sources += [
- "platform_font_skia.cc",
- "platform_font_skia.h",
- "skia_font_delegate.cc",
- "skia_font_delegate.h",
- ]
- }
-
- # iOS.
- if (is_ios) {
- sources += [ "scoped_cg_context_save_gstate_mac.h" ]
- } else {
- public_deps += [ "//cc/paint" ]
- deps += [ "//third_party:freetype_harfbuzz" ]
- }
-
- # Android.
- if (is_android) {
- if (!is_debug) {
- configs -= [ "//build/config/compiler:default_optimization" ]
- configs += [ "//build/config/compiler:optimize_max" ]
- }
-
- deps += [ ":gfx_jni_headers" ]
- libs = [
- "android",
- "jnigraphics",
- ]
- }
-
- if (is_android || is_fuchsia) {
- sources += [
- "font_fallback_skia.cc",
- "font_render_params_skia.cc",
- ]
- }
-
- if (is_android || is_fuchsia || is_win || is_mac) {
- sources += [
- "font_fallback_skia_impl.cc",
- "font_fallback_skia_impl.h",
- ]
- }
-
- if (!is_ios) {
- sources += [
- "bidi_line_iterator.cc",
- "bidi_line_iterator.h",
- "harfbuzz_font_skia.cc",
- "harfbuzz_font_skia.h",
- "paint_vector_icon.cc",
- "paint_vector_icon.h",
- "render_text.cc",
- "render_text.h",
- "render_text_harfbuzz.cc",
- "render_text_harfbuzz.h",
- "text_utils_skia.cc",
- ]
- }
-
- # Windows.
- if (is_win) {
- libs = [
- "setupapi.lib",
- "dwrite.lib",
- ]
- deps += [ "//components/crash/core/common" ]
- } else {
- sources -= [
- "gdi_util.cc",
- "gdi_util.h",
- "icon_util.cc",
- "icon_util.h",
- "sys_color_change_listener.cc",
- "sys_color_change_listener.h",
- ]
- }
-
- # Linux.
- if (is_linux || is_chromeos) {
- deps += [ "//third_party/fontconfig" ]
- }
-
- if (is_mac) {
- frameworks = [
- "AppKit.framework",
- "CoreFoundation.framework",
- "CoreGraphics.framework",
- "CoreText.framework",
- "IOSurface.framework",
- ]
- }
-
- if ((!use_aura && !toolkit_views) || is_ios) {
- sources -= [
- "nine_image_painter.cc",
- "nine_image_painter.h",
- ]
- }
-
- if (use_ozone) {
- deps += [ "//ui/ozone:buildflags" ]
- }
-
- if (ozone_platform_x11 || use_x11) {
- deps += [ "//ui/gfx/x" ]
- }
}
component("color_space") {
sources = [
- "color_space.cc",
+ "//skia/ext/skcolorspace_primaries.cc",
+ "//skia/ext/skcolorspace_primaries.h",
"color_space.h",
"color_space_export.h",
- "display_color_spaces.cc",
- "display_color_spaces.h",
- "hdr_static_metadata.cc",
- "hdr_static_metadata.h",
- "icc_profile.cc",
- "icc_profile.h",
+ "hdr_metadata.cc",
+ "hdr_metadata.h",
"skia_color_space_util.cc",
"skia_color_space_util.h",
]
- if (is_win) {
- sources += [
- "color_space_win.cc",
- "color_space_win.h",
- ]
- }
deps = [
- "//build:chromeos_buildflags",
- "//skia:skcms",
- "//ui/gfx:buffer_types",
- ]
- public_deps = [
"//base",
- "//skia",
+ "//ui/gfx/geometry",
]
- if (is_mac) {
- sources += [
- "mac/display_icc_profiles.cc",
- "mac/display_icc_profiles.h",
- ]
- frameworks = [
- "CoreFoundation.framework",
- "CoreGraphics.framework",
- ]
- }
- if (use_x11) {
- deps += [ "//ui/gfx/x" ]
- }
+ include_dirs = [ "//third_party/skia" ]
defines = [ "COLOR_SPACE_IMPLEMENTATION" ]
}
@@ -470,18 +60,6 @@
sources = [ "image/resize_image_dimensions.h" ]
}
-# Depend on this to use native_widget_types.h without pulling in all of gfx.
-source_set("native_widget_types") {
- public = [ "native_widget_types.h" ]
-
- public_deps = [
- ":gfx_export",
- "//base",
- ]
-
- deps = [ "//build:chromeos_buildflags" ]
-}
-
group("selection_bound") {
if (is_component_build) {
public_deps = [ ":gfx" ]
@@ -516,423 +94,6 @@
sources = [ "buffer_types.h" ]
}
-# The GPU memory buffer stuff is separate from "gfx" to allow GPU-related
-# things to use these files without pulling in all of gfx, which includes large
-# things like Skia.
-#
-# The structure here allows the memory buffer to be part of the gfx component
-# in the component build, but be a separate source set in a static build.
-group("memory_buffer") {
- if (is_component_build) {
- public_deps = [ ":gfx" ]
- } else {
- public_deps = [ ":memory_buffer_sources" ]
- }
-}
-
-# Cannot be a static_library in component builds due to exported functions
-source_set("memory_buffer_sources") {
- visibility = [ ":*" ] # Depend on through ":memory_buffer".
-
- # TODO(brettw) refactor this so these sources are in a coherent directory
- # structure rather than random samplings of ui/gfx and ui/gfx/mac.
- sources = [
- "buffer_format_util.cc",
- "buffer_format_util.h",
- "buffer_usage_util.cc",
- "buffer_usage_util.h",
- "ca_layer_params.cc",
- "ca_layer_params.h",
- "client_native_pixmap.h",
- "client_native_pixmap_factory.h",
- "generic_shared_memory_id.cc",
- "generic_shared_memory_id.h",
- "gfx_export.h",
- "gpu_fence.cc",
- "gpu_fence.h",
- "gpu_fence_handle.cc",
- "gpu_fence_handle.h",
- "hdr_metadata.cc",
- "hdr_metadata.h",
- "native_pixmap.h",
- "overlay_priority_hint.h",
- "overlay_transform.h",
- "surface_origin.h",
- ]
-
- if (!is_ios) {
- sources += [
- "gpu_memory_buffer.cc",
- "gpu_memory_buffer.h",
- ]
- }
-
- configs += [ "//build/config/compiler:wexit_time_destructors" ]
-
- defines = [ "GFX_IMPLEMENTATION" ]
-
- public_deps = [ ":buffer_types" ]
-
- deps = [
- ":gfx_switches",
- ":native_widget_types",
- "//base",
- "//build:chromecast_buildflags",
- "//build:chromeos_buildflags",
- "//ui/gfx/geometry",
- ]
-
- if (is_linux || is_chromeos) {
- sources += [
- "linux/client_native_pixmap_dmabuf.cc",
- "linux/client_native_pixmap_dmabuf.h",
- "linux/client_native_pixmap_factory_dmabuf.cc",
- "linux/client_native_pixmap_factory_dmabuf.h",
- "linux/native_pixmap_dmabuf.cc",
- "linux/native_pixmap_dmabuf.h",
- ]
-
- deps += [ "//build/config/linux/libdrm" ]
- }
-
- if (is_linux || is_chromeos || is_android) {
- deps += [ "//third_party/libsync" ]
- }
-
- if (is_mac) {
- sources += [
- "mac/io_surface.cc",
- "mac/io_surface.h",
- ]
-
- public_deps += [ "//ui/gfx:color_space" ]
- }
-
- if (is_win) {
- public_deps += [ "//ipc:message_support" ]
- }
-
- if ((is_linux || is_chromeos || use_ozone) && !is_nacl) {
- sources += [
- "native_pixmap_handle.cc",
- "native_pixmap_handle.h",
- ]
- }
-}
-
-# TODO(ccameron): This can be moved into a separate source_set.
-component("gfx_switches") {
- sources = [
- "switches.cc",
- "switches.h",
- "switches_export.h",
- ]
-
- defines = [ "GFX_SWITCHES_IMPLEMENTATION" ]
-
- deps = [ "//base" ]
-}
-
-static_library("test_support") {
- testonly = true
- sources = [
- "animation/animation_test_api.cc",
- "animation/animation_test_api.h",
- "animation/keyframe/test/animation_utils.cc",
- "animation/keyframe/test/animation_utils.h",
- "animation/test_animation_delegate.h",
- "geometry/test/rect_test_util.cc",
- "geometry/test/rect_test_util.h",
- "geometry/test/size_test_util.h",
- "geometry/test/transform_test_util.cc",
- "geometry/test/transform_test_util.h",
- "image/image_unittest_util.cc",
- "image/image_unittest_util.h",
- "test/font_fallback_test_data.cc",
- "test/font_fallback_test_data.h",
- "test/gfx_util.cc",
- "test/gfx_util.h",
- "test/icc_profiles.cc",
- "test/icc_profiles.h",
- ]
- if (is_ios) {
- sources += [ "image/image_unittest_util_ios.mm" ]
- }
- if (is_mac) {
- sources += [ "image/image_unittest_util_mac.mm" ]
- }
-
- public_deps = [ ":gfx" ]
-
- deps = [
- "//base",
- "//base/test:test_support",
- "//skia",
- "//testing/gtest",
- "//ui/gfx/animation",
- "//ui/gfx/animation/keyframe",
- "//ui/gfx/geometry",
- ]
-
- if (!is_ios) {
- sources += [ "render_text_test_api.h" ]
-
- deps += [ "//third_party:freetype_harfbuzz" ]
- }
-}
-
-if (is_mac) {
- component("gfx_io_surface_hdr_metadata") {
- sources = [
- "mac/io_surface_hdr_metadata.cc",
- "mac/io_surface_hdr_metadata.h",
- ]
- defines = [ "IS_GFX_IO_SURFACE_HDR_METADATA_IMPL" ]
-
- # This is a separate component from the other sources because it depends on
- # the mojo serialize and deserialize methods.
- deps = [
- ":gfx",
- "//ui/gfx/mojom:mojom",
- ]
- frameworks = [
- "CoreFoundation.framework",
- "IOSurface.framework",
- ]
- }
-}
-
-test("gfx_unittests") {
- sources = [
- "animation/keyframe/keyframe_animation_unittest.cc",
- "animation/keyframe/keyframed_animation_curve_unittest.cc",
- "font_names_testing.cc",
- "font_names_testing.h",
- "font_unittest.cc",
- "geometry/rrect_f_unittest.cc",
- "geometry/transform_operations_unittest.cc",
- "geometry/transform_unittest.cc",
- "image/buffer_w_stream_unittest.cc",
- "image/image_family_unittest.cc",
- "image/image_skia_unittest.cc",
- "image/image_unittest.cc",
- "interpolated_transform_unittest.cc",
- "test/run_all_unittests.cc",
- "text_elider_unittest.cc",
- "text_utils_unittest.cc",
- ]
- if (is_linux || is_chromeos) {
- sources += [
- "font_fallback_linux_unittest.cc",
- "font_render_params_linux_unittest.cc",
- ]
- }
- if (is_mac) {
- sources += [
- "font_fallback_mac_unittest.cc",
- "image/image_mac_unittest.mm",
- "mac/coordinate_conversion_unittest.mm",
- "mac/io_surface_unittest.cc",
- "path_mac_unittest.mm",
- "platform_font_mac_unittest.mm",
- "range/range_mac_unittest.mm",
- ]
- frameworks = [ "IOSurface.framework" ]
- }
- if (is_win) {
- sources += [ "font_fallback_win_unittest.cc" ]
- }
- if (is_ios) {
- sources += [
- "image/image_ios_unittest.mm",
- "ios/NSString+CrStringDrawing_unittest.mm",
- "ios/uikit_util_unittest.mm",
- ]
- }
- if (is_android) {
- sources += [ "android/android_surface_control_compat_unittest.cc" ]
- }
-
- include_dirs = [ "//third_party/skia/include/private" ]
-
- data = [ "test/data/" ]
-
- if (!is_ios) {
- sources += [
- "animation/animation_container_unittest.cc",
- "animation/animation_runner_unittest.cc",
- "animation/animation_unittest.cc",
- "animation/multi_animation_unittest.cc",
- "animation/slide_animation_unittest.cc",
- "animation/tween_unittest.cc",
- "blit_unittest.cc",
- "break_list_unittest.cc",
- "canvas_unittest.cc",
- "codec/jpeg_codec_unittest.cc",
- "codec/png_codec_unittest.cc",
- "color_analysis_unittest.cc",
- "color_space_unittest.cc",
- "color_transform_unittest.cc",
- "color_utils_unittest.cc",
- "delegated_ink_unittest.cc",
- "font_fallback_unittest.cc",
- "font_list_unittest.cc",
- "geometry/axis_transform2d_unittest.cc",
- "geometry/box_unittest.cc",
- "geometry/cubic_bezier_unittest.cc",
- "geometry/insets_unittest.cc",
- "geometry/matrix3_unittest.cc",
- "geometry/point3_unittest.cc",
- "geometry/point_unittest.cc",
- "geometry/quad_unittest.cc",
- "geometry/quaternion_unittest.cc",
- "geometry/rect_f_unittest.cc",
- "geometry/rect_unittest.cc",
- "geometry/resize_utils_unittest.cc",
- "geometry/rounded_corners_f_unittest.cc",
- "geometry/size_unittest.cc",
- "geometry/transform_util_unittest.cc",
- "geometry/vector2d_unittest.cc",
- "geometry/vector3d_unittest.cc",
- "half_float_unittest.cc",
- "icc_profile_unittest.cc",
- "image/image_skia_operations_unittest.cc",
- "image/image_util_unittest.cc",
- "mojom/mojom_traits_unittest.cc",
- "nine_image_painter_unittest.cc",
- "overlay_transform_utils_unittest.cc",
- "paint_vector_icon_unittest.cc",
- "range/range_unittest.cc",
- "selection_bound_unittest.cc",
- "selection_model_unittest.cc",
- "sequential_id_generator_unittest.cc",
- "shadow_value_unittest.cc",
- "skbitmap_operations_unittest.cc",
- "skia_util_unittest.cc",
- "skrect_conversion_unittest.cc",
- "utf16_indexing_unittest.cc",
- ]
- }
-
- if (is_win) {
- sources += [ "system_fonts_win_unittest.cc" ]
- }
-
- if (is_linux || is_chromeos || is_android || is_fuchsia || is_win) {
- sources += [ "platform_font_skia_unittest.cc" ]
- }
-
- deps = [
- ":gfx",
- ":test_support",
- "//base",
- "//base/test:test_support",
- "//build:chromeos_buildflags",
- "//skia",
- "//skia:skcms",
- "//testing/gtest",
- "//third_party/icu:icuuc",
- "//third_party/libpng",
- "//third_party/zlib",
- "//ui/base",
- "//ui/gfx/animation",
- "//ui/gfx/animation/keyframe",
- "//ui/gfx/geometry",
- "//ui/gfx/range",
- ]
-
- if (!is_ios) {
- sources += [
- "bidi_line_iterator_unittest.cc",
- "render_text_unittest.cc",
- ]
- deps += [ "//third_party:freetype_harfbuzz" ]
- }
-
- data_deps = [ "//ui/resources:ui_test_pak_data" ]
-
- if (is_apple) {
- deps += [ "//ui/resources:ui_test_pak_bundle_data" ]
- }
-
- if (is_mac) {
- deps += [ ":gfx_io_surface_hdr_metadata" ]
- }
-
- if (is_android) {
- deps += [ "//ui/android:ui_java" ]
- }
-
- if (is_android || is_fuchsia) {
- sources += [ "font_fallback_skia_unittest.cc" ]
- }
-
- if (!use_aura && !is_ios) {
- sources -= [ "nine_image_painter_unittest.cc" ]
- }
-
- if (is_win) {
- sources += [
- "icon_util_unittest.cc",
- "icon_util_unittests.rc",
- "icon_util_unittests_resource.h",
- "path_win_unittest.cc",
- "win/crash_id_helper_unittest.cc",
- "win/direct_write_unittest.cc",
- "win/text_analysis_source_unittest.cc",
- ]
-
- ldflags = [
- "/DELAYLOAD:d2d1.dll",
- "/DELAYLOAD:d3d10_1.dll",
- ]
-
- libs = [
- "d2d1.lib",
- "d3d10_1.lib",
- "dwrite.lib",
- "imm32.lib",
- "oleacc.lib",
- ]
- }
-
- if (!is_ios) {
- deps += [
- "//cc/paint",
- "//mojo/core/embedder",
- "//mojo/public/cpp/bindings",
- "//mojo/public/cpp/test_support:test_utils",
- "//ui/gfx/geometry/mojom:unit_test",
- "//ui/gfx/image/mojom:unit_test",
- "//ui/gfx/mojom:test_interfaces",
- "//ui/gfx/range/mojom:unit_test",
- ]
- }
-
- if (is_linux || is_chromeos) {
- sources += [
- "linux/fontconfig_util_unittest.cc",
- "linux/native_pixmap_dmabuf_unittest.cc",
- ]
- deps += [ "//third_party/fontconfig" ]
- }
-
- if (is_fuchsia) {
- deps += [ "//skia:test_fonts" ]
- }
-}
-
-if (is_android) {
- generate_jni("gfx_jni_headers") {
- sources = [
- "../android/java/src/org/chromium/ui/gfx/AdpfRenderingStageScheduler.java",
- "../android/java/src/org/chromium/ui/gfx/Animation.java",
- "../android/java/src/org/chromium/ui/gfx/BitmapHelper.java",
- "../android/java/src/org/chromium/ui/gfx/ViewConfigurationHelper.java",
- ]
- }
-}
-
fuzzer_test("color_analysis_fuzzer") {
sources = [ "color_analysis_fuzzer.cc" ]
@@ -973,3 +134,10 @@
dict = "test/data/render_text/unicode_text_fuzzer.dict"
}
+
+if (is_ios) {
+ bundle_data_from_filelist("unit_tests_bundle_data") {
+ testonly = true
+ filelist_name = "test/data/unit_tests_bundle_data.filelist"
+ }
+}
diff --git a/ui/gfx/DEPS b/ui/gfx/DEPS
index bff9445..75bd058 100644
--- a/ui/gfx/DEPS
+++ b/ui/gfx/DEPS
@@ -7,7 +7,9 @@
"+third_party/harfbuzz-ng",
"+third_party/skia",
"+third_party/test_fonts",
+ "+ui/base/ui_base_features.h",
"+ui/ios",
+ "+ui/linux",
"+ui/ozone/buildflags.h",
"-testing/gmock",
diff --git a/ui/gfx/METADATA b/ui/gfx/METADATA
index 6ed0bf4..0d44a71 100644
--- a/ui/gfx/METADATA
+++ b/ui/gfx/METADATA
@@ -1,12 +1,14 @@
+name: "ui-gfx"
+
third_party {
identifier {
type: "ChromiumVersion"
- value: "96.0.4664.219" # from https://chromereleases.googleblog.com/2022/08/long-term-support-channel-update-for_31.html
+ value: "114.0.5735.358" # from https://chromereleases.googleblog.com/2024/03/long-term-support-channel-update-for_26.html
}
identifier {
type: "Git"
value: "https://chromium.googlesource.com/chromium/src.git"
- version: "6a496db5ef7219101beacceca9566367c9cb1a09"
+ version: "1759c6ae9316996b9f150c0ce9d0ca78a3d15c02"
}
identifier {
type: "UpstreamSubdir"
diff --git a/ui/gfx/OWNERS b/ui/gfx/OWNERS
index 4bec2f1..b1517a0 100644
--- a/ui/gfx/OWNERS
+++ b/ui/gfx/OWNERS
@@ -15,6 +15,9 @@
# Color utils.
per-file color_palette.h=pkasting@chromium.org
per-file color_utils*=pkasting@chromium.org
+per-file color_conversions*=fserb@chromium.org
+per-file color_conversions*=ccameron@chromium.org
+per-file color_conversions*=juanmihd@chromium.org
# Display and related classes.
per-file display*=oshima@chromium.org
@@ -23,11 +26,9 @@
# Canvas painting.
per-file canvas*=danakj@chromium.org
-# Overlay transforms.
+# Overlay states, configurations, etc.
per-file overlay*=spang@chromium.org
-
-# Overlay plane data.
-per-file overlay_plane_data*=rjkroege@chromium.org
+per-file overlay*=rjkroege@chromium.org
# Transform, interpolated transform and transform util.
per-file transform*=danakj@chromium.org
diff --git a/ui/gfx/PRESUBMIT.py b/ui/gfx/PRESUBMIT.py
new file mode 100644
index 0000000..724d23d
--- /dev/null
+++ b/ui/gfx/PRESUBMIT.py
@@ -0,0 +1,26 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Presubmit checks for ui/gfx
+
+See https://www.chromium.org/developers/how-tos/depottools/presubmit-scripts
+for more details about the presubmit API built into depot_tools.
+"""
+
+PRESUBMIT_VERSION = '2.0.0'
+
+USE_PYTHON3 = True
+
+def CheckChange(input_api, output_api):
+ import sys
+ old_sys_path = sys.path[:]
+ results = []
+ try:
+ sys.path.append(input_api.change.RepositoryRoot())
+ from build.ios import presubmit_support
+ results += presubmit_support.CheckBundleData(
+ input_api, output_api, 'test/data/unit_tests_bundle_data')
+ finally:
+ sys.path = old_sys_path
+ return results
diff --git a/ui/gfx/android/achoreographer_compat.cc b/ui/gfx/android/achoreographer_compat.cc
new file mode 100644
index 0000000..49cccfa
--- /dev/null
+++ b/ui/gfx/android/achoreographer_compat.cc
@@ -0,0 +1,78 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/android/achoreographer_compat.h"
+
+#include <dlfcn.h>
+
+#include "base/android/build_info.h"
+#include "base/logging.h"
+
+#define LOAD_FUNCTION(lib, func) \
+ do { \
+ func##Fn = reinterpret_cast<p##func>(dlsym(lib, #func)); \
+ if (!func##Fn) { \
+ supported = false; \
+ LOG(ERROR) << "Unable to load function " << #func; \
+ } \
+ } while (0)
+
+namespace gfx {
+
+// static
+const AChoreographerCompat& AChoreographerCompat::Get() {
+ static AChoreographerCompat instance;
+ return instance;
+}
+
+AChoreographerCompat::AChoreographerCompat() {
+ void* main_dl_handle = dlopen("libandroid.so", RTLD_NOW);
+ if (!main_dl_handle) {
+ LOG(ERROR) << "Couldnt load libandroid.so";
+ supported = false;
+ return;
+ }
+
+ LOAD_FUNCTION(main_dl_handle, AChoreographer_getInstance);
+ LOAD_FUNCTION(main_dl_handle, AChoreographer_postFrameCallback64);
+ LOAD_FUNCTION(main_dl_handle, AChoreographer_registerRefreshRateCallback);
+ LOAD_FUNCTION(main_dl_handle, AChoreographer_unregisterRefreshRateCallback);
+}
+
+// static
+const AChoreographerCompat33& AChoreographerCompat33::Get() {
+ static AChoreographerCompat33 instance;
+ return instance;
+}
+
+AChoreographerCompat33::AChoreographerCompat33() {
+ if (!base::android::BuildInfo::GetInstance()->is_at_least_t()) {
+ supported = false;
+ return;
+ }
+
+ void* main_dl_handle = dlopen("libandroid.so", RTLD_NOW);
+ if (!main_dl_handle) {
+ LOG(ERROR) << "Couldnt load libandroid.so";
+ supported = false;
+ return;
+ }
+
+ LOAD_FUNCTION(main_dl_handle, AChoreographer_postVsyncCallback);
+ LOAD_FUNCTION(main_dl_handle,
+ AChoreographerFrameCallbackData_getFrameTimeNanos);
+ LOAD_FUNCTION(main_dl_handle,
+ AChoreographerFrameCallbackData_getFrameTimelinesLength);
+ LOAD_FUNCTION(main_dl_handle,
+ AChoreographerFrameCallbackData_getPreferredFrameTimelineIndex);
+ LOAD_FUNCTION(main_dl_handle,
+ AChoreographerFrameCallbackData_getFrameTimelineVsyncId);
+ LOAD_FUNCTION(
+ main_dl_handle,
+ AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos);
+ LOAD_FUNCTION(main_dl_handle,
+ AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos);
+}
+
+} // namespace gfx
diff --git a/ui/gfx/android/achoreographer_compat.h b/ui/gfx/android/achoreographer_compat.h
new file mode 100644
index 0000000..8128742
--- /dev/null
+++ b/ui/gfx/android/achoreographer_compat.h
@@ -0,0 +1,93 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_ANDROID_ACHOREOGRAPHER_COMPAT_H_
+#define UI_GFX_ANDROID_ACHOREOGRAPHER_COMPAT_H_
+
+#include <sys/types.h>
+
+#include "ui/gfx/gfx_export.h"
+
+extern "C" {
+typedef struct AChoreographer AChoreographer;
+typedef void (*AChoreographer_frameCallback64)(int64_t, void*);
+typedef void (*AChoreographer_refreshRateCallback)(int64_t, void*);
+
+using pAChoreographer_getInstance = AChoreographer* (*)();
+using pAChoreographer_postFrameCallback64 =
+ void (*)(AChoreographer*, AChoreographer_frameCallback64, void*);
+using pAChoreographer_registerRefreshRateCallback =
+ void (*)(AChoreographer*, AChoreographer_refreshRateCallback, void*);
+using pAChoreographer_unregisterRefreshRateCallback =
+ void (*)(AChoreographer*, AChoreographer_refreshRateCallback, void*);
+
+typedef struct AChoreographerFrameCallbackData AChoreographerFrameCallbackData;
+typedef void (*AChoreographer_vsyncCallback)(
+ const AChoreographerFrameCallbackData*,
+ void*);
+
+using pAChoreographer_postVsyncCallback =
+ void (*)(AChoreographer* choreographer,
+ AChoreographer_vsyncCallback callback,
+ void* data);
+using pAChoreographerFrameCallbackData_getFrameTimeNanos =
+ int64_t (*)(const AChoreographerFrameCallbackData*);
+using pAChoreographerFrameCallbackData_getFrameTimelinesLength =
+ size_t (*)(const AChoreographerFrameCallbackData*);
+using pAChoreographerFrameCallbackData_getPreferredFrameTimelineIndex =
+ size_t (*)(const AChoreographerFrameCallbackData*);
+using pAChoreographerFrameCallbackData_getFrameTimelineVsyncId =
+ int64_t (*)(const AChoreographerFrameCallbackData*, size_t);
+using pAChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos =
+ int64_t (*)(const AChoreographerFrameCallbackData*, size_t);
+using pAChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos =
+ int64_t (*)(const AChoreographerFrameCallbackData*, size_t);
+} // extern "C"
+
+namespace gfx {
+
+struct GFX_EXPORT AChoreographerCompat {
+ static GFX_EXPORT const AChoreographerCompat& Get();
+
+ bool supported = true;
+ pAChoreographer_getInstance AChoreographer_getInstanceFn = nullptr;
+ pAChoreographer_postFrameCallback64 AChoreographer_postFrameCallback64Fn =
+ nullptr;
+ pAChoreographer_registerRefreshRateCallback
+ AChoreographer_registerRefreshRateCallbackFn = nullptr;
+ pAChoreographer_unregisterRefreshRateCallback
+ AChoreographer_unregisterRefreshRateCallbackFn = nullptr;
+
+ private:
+ AChoreographerCompat();
+};
+
+struct GFX_EXPORT AChoreographerCompat33 {
+ static GFX_EXPORT const AChoreographerCompat33& Get();
+
+ bool supported = true;
+ pAChoreographer_postVsyncCallback AChoreographer_postVsyncCallbackFn =
+ nullptr;
+ pAChoreographerFrameCallbackData_getFrameTimeNanos
+ AChoreographerFrameCallbackData_getFrameTimeNanosFn = nullptr;
+ pAChoreographerFrameCallbackData_getFrameTimelinesLength
+ AChoreographerFrameCallbackData_getFrameTimelinesLengthFn = nullptr;
+ pAChoreographerFrameCallbackData_getPreferredFrameTimelineIndex
+ AChoreographerFrameCallbackData_getPreferredFrameTimelineIndexFn =
+ nullptr;
+ pAChoreographerFrameCallbackData_getFrameTimelineVsyncId
+ AChoreographerFrameCallbackData_getFrameTimelineVsyncIdFn = nullptr;
+ pAChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanos
+ AChoreographerFrameCallbackData_getFrameTimelineExpectedPresentationTimeNanosFn =
+ nullptr;
+ pAChoreographerFrameCallbackData_getFrameTimelineDeadlineNanos
+ AChoreographerFrameCallbackData_getFrameTimelineDeadlineNanosFn = nullptr;
+
+ private:
+ AChoreographerCompat33();
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_ANDROID_ACHOREOGRAPHER_COMPAT_H_
diff --git a/ui/gfx/android/android_surface_control_compat.cc b/ui/gfx/android/android_surface_control_compat.cc
index a92788e..9c8078d 100644
--- a/ui/gfx/android/android_surface_control_compat.cc
+++ b/ui/gfx/android/android_surface_control_compat.cc
@@ -1,22 +1,29 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/android/android_surface_control_compat.h"
#include <android/data_space.h>
+#include <android/hdr_metadata.h>
#include <dlfcn.h>
#include "base/android/build_info.h"
#include "base/atomic_sequence_num.h"
-#include "base/bind.h"
-#include "base/bind_post_task.h"
+#include "base/containers/flat_set.h"
#include "base/debug/crash_logging.h"
+#include "base/debug/dump_without_crashing.h"
+#include "base/functional/bind.h"
#include "base/hash/md5_constexpr.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
+#include "base/memory/raw_ptr.h"
+#include "base/no_destructor.h"
#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/lock.h"
#include "base/system/sys_info.h"
+#include "base/task/bind_post_task.h"
+#include "base/task/single_thread_task_runner.h"
#include "base/trace_event/trace_event.h"
#include "ui/gfx/color_space.h"
@@ -32,6 +39,7 @@
ASurfaceControl* (*)(ANativeWindow* parent, const char* name);
using pASurfaceControl_create = ASurfaceControl* (*)(ASurfaceControl* parent,
const char* name);
+using pASurfaceControl_fromJava = ASurfaceControl* (*)(JNIEnv*, jobject);
using pASurfaceControl_release = void (*)(ASurfaceControl*);
// ASurfaceTransaction enums
@@ -41,12 +49,6 @@
ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE = 2,
};
-// ANativeWindow_FrameRateCompatibility enums
-enum {
- ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_DEFAULT = 0,
- ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1
-};
-
// ASurfaceTransaction
using pASurfaceTransaction_create = ASurfaceTransaction* (*)(void);
using pASurfaceTransaction_delete = void (*)(ASurfaceTransaction*);
@@ -97,11 +99,26 @@
void (*)(ASurfaceTransaction* transaction,
ASurfaceControl* surface,
uint64_t data_space);
+using pASurfaceTransaction_setHdrMetadata_cta861_3 =
+ void (*)(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface,
+ struct AHdrMetadata_cta861_3* metadata);
+using pASurfaceTransaction_setHdrMetadata_smpte2086 =
+ void (*)(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface,
+ struct AHdrMetadata_smpte2086* metadata);
+using pASurfaceTransaction_setExtendedRangeBrightness =
+ void (*)(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control,
+ float currentBufferRatio,
+ float desiredRatio);
using pASurfaceTransaction_setFrameRate =
void (*)(ASurfaceTransaction* transaction,
ASurfaceControl* surface_control,
float frameRate,
int8_t compatibility);
+using pASurfaceTransaction_setFrameTimeline =
+ void (*)(ASurfaceTransaction* transaction, int64_t vsync_id);
using pASurfaceTransaction_reparent = void (*)(ASurfaceTransaction*,
ASurfaceControl* surface_control,
ASurfaceControl* new_parent);
@@ -118,6 +135,10 @@
void (*)(ASurfaceControl** surface_controls);
using pASurfaceTransactionStats_getPreviousReleaseFenceFd =
int (*)(ASurfaceTransactionStats* stats, ASurfaceControl* surface_control);
+using pASurfaceTransaction_setEnableBackPressure =
+ void (*)(ASurfaceTransaction* transaction,
+ ASurfaceControl* surface_control,
+ bool enable_back_pressure);
}
namespace gfx {
@@ -155,9 +176,9 @@
void InitWithStubs() {
struct TransactionStub {
ASurfaceTransaction_OnComplete on_complete = nullptr;
- void* on_complete_ctx = nullptr;
+ raw_ptr<void> on_complete_ctx = nullptr;
ASurfaceTransaction_OnCommit on_commit = nullptr;
- void* on_commit_ctx = nullptr;
+ raw_ptr<void> on_commit_ctx = nullptr;
};
ASurfaceTransaction_createFn = []() {
@@ -212,6 +233,7 @@
LOAD_FUNCTION(main_dl_handle, ASurfaceControl_createFromWindow);
LOAD_FUNCTION(main_dl_handle, ASurfaceControl_create);
+ LOAD_FUNCTION_MAYBE(main_dl_handle, ASurfaceControl_fromJava);
LOAD_FUNCTION(main_dl_handle, ASurfaceControl_release);
LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_create);
@@ -230,7 +252,12 @@
LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setBufferTransparency);
LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setDamageRegion);
LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setBufferDataSpace);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setHdrMetadata_cta861_3);
+ LOAD_FUNCTION(main_dl_handle, ASurfaceTransaction_setHdrMetadata_smpte2086);
+ LOAD_FUNCTION_MAYBE(main_dl_handle,
+ ASurfaceTransaction_setExtendedRangeBrightness);
LOAD_FUNCTION_MAYBE(main_dl_handle, ASurfaceTransaction_setFrameRate);
+ LOAD_FUNCTION_MAYBE(main_dl_handle, ASurfaceTransaction_setFrameTimeline);
LOAD_FUNCTION(main_dl_handle, ASurfaceTransactionStats_getPresentFenceFd);
LOAD_FUNCTION(main_dl_handle, ASurfaceTransactionStats_getLatchTime);
@@ -239,6 +266,8 @@
ASurfaceTransactionStats_releaseASurfaceControls);
LOAD_FUNCTION(main_dl_handle,
ASurfaceTransactionStats_getPreviousReleaseFenceFd);
+ LOAD_FUNCTION_MAYBE(main_dl_handle,
+ ASurfaceTransaction_setEnableBackPressure);
}
~SurfaceControlMethods() = default;
@@ -247,6 +276,7 @@
// Surface methods.
pASurfaceControl_createFromWindow ASurfaceControl_createFromWindowFn;
pASurfaceControl_create ASurfaceControl_createFn;
+ pASurfaceControl_fromJava ASurfaceControl_fromJavaFn;
pASurfaceControl_release ASurfaceControl_releaseFn;
// Transaction methods.
@@ -268,7 +298,17 @@
pASurfaceTransaction_setDamageRegion ASurfaceTransaction_setDamageRegionFn;
pASurfaceTransaction_setBufferDataSpace
ASurfaceTransaction_setBufferDataSpaceFn;
+ pASurfaceTransaction_setHdrMetadata_cta861_3
+ ASurfaceTransaction_setHdrMetadata_cta861_3Fn;
+ pASurfaceTransaction_setHdrMetadata_smpte2086
+ ASurfaceTransaction_setHdrMetadata_smpte2086Fn;
+ pASurfaceTransaction_setExtendedRangeBrightness
+ ASurfaceTransaction_setExtendedRangeBrightnessFn;
+
pASurfaceTransaction_setFrameRate ASurfaceTransaction_setFrameRateFn;
+ pASurfaceTransaction_setFrameTimeline ASurfaceTransaction_setFrameTimelineFn;
+ pASurfaceTransaction_setEnableBackPressure
+ ASurfaceTransaction_setEnableBackPressureFn;
// TransactionStats methods.
pASurfaceTransactionStats_getPresentFenceFd
@@ -311,18 +351,103 @@
return ANATIVEWINDOW_TRANSFORM_IDENTITY;
}
+// Remove this and use ADataSpace when SDK will roll. Note, this doesn't define
+// any new data spaces, just defines a primary(standard)/transfer/range
+// separately.
+enum DataSpace : uint64_t {
+ // Primaries
+ STANDARD_BT709 = 1 << 16,
+ STANDARD_BT601_625 = 2 << 16,
+ STANDARD_BT601_525 = 4 << 16,
+ STANDARD_BT2020 = 6 << 16,
+ // Transfer functions
+ TRANSFER_LINEAR = 1 << 22,
+ TRANSFER_SRGB = 2 << 22,
+ TRANSFER_SMPTE_170M = 3 << 22,
+ TRANSFER_ST2084 = 7 << 22,
+ TRANSFER_HLG = 8 << 22,
+ // Ranges;
+ RANGE_FULL = 1 << 27,
+ RANGE_LIMITED = 2 << 27,
+ RANGE_EXTENDED = 3 << 27,
+ RANGE_MASK = 7 << 27,
+
+ ADATASPACE_DCI_P3 = 155844608
+};
+
+absl::optional<uint64_t> GetDataSpaceStandard(
+ const gfx::ColorSpace& color_space) {
+ switch (color_space.GetPrimaryID()) {
+ case gfx::ColorSpace::PrimaryID::BT709:
+ return DataSpace::STANDARD_BT709;
+ case gfx::ColorSpace::PrimaryID::BT470BG:
+ return DataSpace::STANDARD_BT601_625;
+ case gfx::ColorSpace::PrimaryID::SMPTE170M:
+ return DataSpace::STANDARD_BT601_525;
+ case gfx::ColorSpace::PrimaryID::BT2020:
+ return DataSpace::STANDARD_BT2020;
+ default:
+ return absl::nullopt;
+ }
+}
+
+absl::optional<uint64_t> GetDataSpaceTransfer(
+ const gfx::ColorSpace& color_space) {
+ switch (color_space.GetTransferID()) {
+ case gfx::ColorSpace::TransferID::SMPTE170M:
+ return DataSpace::TRANSFER_SMPTE_170M;
+ case gfx::ColorSpace::TransferID::LINEAR_HDR:
+ return DataSpace::TRANSFER_LINEAR;
+ case gfx::ColorSpace::TransferID::PQ:
+ return DataSpace::TRANSFER_ST2084;
+ case gfx::ColorSpace::TransferID::HLG:
+ return DataSpace::TRANSFER_HLG;
+ // We use SRGB for BT709. See |ColorSpace::GetTransferFunction()| for
+ // details.
+ case gfx::ColorSpace::TransferID::BT709:
+ return DataSpace::TRANSFER_SRGB;
+ default:
+ return absl::nullopt;
+ }
+}
+
+absl::optional<uint64_t> GetDataSpaceRange(const gfx::ColorSpace& color_space) {
+ switch (color_space.GetRangeID()) {
+ case gfx::ColorSpace::RangeID::FULL:
+ return DataSpace::RANGE_FULL;
+ case gfx::ColorSpace::RangeID::LIMITED:
+ return DataSpace::RANGE_LIMITED;
+ default:
+ return absl::nullopt;
+ };
+}
+
uint64_t ColorSpaceToADataSpace(const gfx::ColorSpace& color_space) {
if (!color_space.IsValid() || color_space == gfx::ColorSpace::CreateSRGB())
return ADATASPACE_SRGB;
- if (color_space == gfx::ColorSpace::CreateSCRGBLinear())
+ if (color_space == gfx::ColorSpace::CreateSRGBLinear())
return ADATASPACE_SCRGB_LINEAR;
if (color_space == gfx::ColorSpace::CreateDisplayP3D65())
return ADATASPACE_DISPLAY_P3;
- // TODO(khushalsagar): Check if we can support BT2020 using
- // ADATASPACE_BT2020_PQ.
+ if (base::android::BuildInfo::GetInstance()->sdk_int() >=
+ base::android::SDK_VERSION_S) {
+ if (color_space == gfx::ColorSpace::CreateExtendedSRGB()) {
+ return DataSpace::STANDARD_BT709 | DataSpace::TRANSFER_SRGB |
+ DataSpace::RANGE_EXTENDED;
+ }
+
+ auto standard = GetDataSpaceStandard(color_space);
+ auto transfer = GetDataSpaceTransfer(color_space);
+ auto range = GetDataSpaceRange(color_space);
+
+ // Data space is set of the flags, so check if all components are valid.
+ if (standard && transfer && range)
+ return standard.value() | transfer.value() | range.value();
+ }
+
return ADATASPACE_UNKNOWN;
}
@@ -377,6 +502,16 @@
return kMask ^ transaction_id;
}
+base::Lock& GetGlobalLock() {
+ static base::NoDestructor<base::Lock> lock;
+ return *lock;
+}
+
+base::flat_set<int>& GetGlobalPendingCompleteCallbackIds() {
+ static base::NoDestructor<base::flat_set<int>> set;
+ return *set;
+}
+
// Note that the framework API states that this callback can be dispatched on
// any thread (in practice it should be a binder thread).
void OnTransactionCompletedOnAnyThread(void* context,
@@ -389,6 +524,17 @@
"toplevel.flow", "gfx::SurfaceControlTransaction completed",
GetTraceIdForTransaction(ack_ctx->id), TRACE_EVENT_FLAG_FLOW_IN);
+ bool dump = false;
+ {
+ base::AutoLock lock(GetGlobalLock());
+ size_t num_removed =
+ GetGlobalPendingCompleteCallbackIds().erase(ack_ctx->id);
+ dump = !num_removed;
+ }
+ if (dump) {
+ base::debug::DumpWithoutCrashing(base::Location::Current(), base::Days(1));
+ }
+
std::move(ack_ctx->callback).Run(std::move(transaction_stats));
delete ack_ctx;
}
@@ -450,6 +596,23 @@
nullptr;
}
+bool SurfaceControl::SupportsSetFrameTimeline() {
+ return IsSupported() &&
+ SurfaceControlMethods::Get().ASurfaceTransaction_setFrameTimelineFn !=
+ nullptr;
+}
+
+bool SurfaceControl::SupportsSurfacelessControl() {
+ return IsSupported() &&
+ !!SurfaceControlMethods::Get().ASurfaceControl_fromJavaFn;
+}
+
+bool SurfaceControl::SupportsSetEnableBackPressure() {
+ return IsSupported() &&
+ SurfaceControlMethods::Get()
+ .ASurfaceTransaction_setEnableBackPressureFn != nullptr;
+}
+
void SurfaceControl::SetStubImplementationForTesting() {
SurfaceControlMethods::GetImpl(/*load_functions=*/false).InitWithStubs();
}
@@ -485,6 +648,19 @@
surface_ = owned_surface_;
}
+SurfaceControl::Surface::Surface(
+ JNIEnv* env,
+ const base::android::JavaRef<jobject>& j_surface_control) {
+ CHECK(SupportsSurfacelessControl());
+ owned_surface_ = SurfaceControlMethods::Get().ASurfaceControl_fromJavaFn(
+ env, j_surface_control.obj());
+ if (!owned_surface_) {
+ LOG(ERROR) << "Failed to obtain ASurfaceControl from java";
+ return;
+ }
+ surface_ = owned_surface_;
+}
+
SurfaceControl::Surface::~Surface() {
if (owned_surface_)
SurfaceControlMethods::Get().ASurfaceControl_releaseFn(owned_surface_);
@@ -512,31 +688,45 @@
}
SurfaceControl::Transaction::~Transaction() {
- if (transaction_)
- SurfaceControlMethods::Get().ASurfaceTransaction_deleteFn(transaction_);
+ DestroyIfNeeded();
+}
+
+void SurfaceControl::Transaction::DestroyIfNeeded() {
+ if (!transaction_)
+ return;
+ if (need_to_apply_)
+ SurfaceControlMethods::Get().ASurfaceTransaction_applyFn(transaction_);
+ SurfaceControlMethods::Get().ASurfaceTransaction_deleteFn(transaction_);
+ transaction_ = nullptr;
}
SurfaceControl::Transaction::Transaction(Transaction&& other)
: id_(other.id_),
transaction_(other.transaction_),
on_commit_cb_(std::move(other.on_commit_cb_)),
- on_complete_cb_(std::move(other.on_complete_cb_)) {
+ on_complete_cb_(std::move(other.on_complete_cb_)),
+ need_to_apply_(other.need_to_apply_) {
other.transaction_ = nullptr;
other.id_ = 0;
+ other.need_to_apply_ = false;
}
SurfaceControl::Transaction& SurfaceControl::Transaction::operator=(
Transaction&& other) {
- if (transaction_)
- SurfaceControlMethods::Get().ASurfaceTransaction_deleteFn(transaction_);
+ if (this == &other)
+ return *this;
+
+ DestroyIfNeeded();
transaction_ = other.transaction_;
id_ = other.id_;
on_commit_cb_ = std::move(other.on_commit_cb_);
on_complete_cb_ = std::move(other.on_complete_cb_);
+ need_to_apply_ = other.need_to_apply_;
other.transaction_ = nullptr;
other.id_ = 0;
+ other.need_to_apply_ = false;
return *this;
}
@@ -557,6 +747,13 @@
SurfaceControlMethods::Get().ASurfaceTransaction_setBufferFn(
transaction_, surface.surface(), buffer,
fence_fd.is_valid() ? fence_fd.release() : -1);
+ // In T OS, setBuffer call setOnComplete internally, so Apply() is required to
+ // decrease ref count of SurfaceControl.
+ // TODO(crbug.com/1395271): remove this if AOSP fix the issue
+ if (base::android::BuildInfo::GetInstance()->sdk_int() >=
+ base::android::SDK_VERSION_T) {
+ need_to_apply_ = true;
+ }
}
void SurfaceControl::Transaction::SetGeometry(const Surface& surface,
@@ -590,6 +787,12 @@
transaction_, surface.surface(), RectToARect(rect));
}
+void SurfaceControl::Transaction::SetFrameTimelineId(int64_t vsync_id) {
+ CHECK(SurfaceControlMethods::Get().ASurfaceTransaction_setFrameTimelineFn);
+ SurfaceControlMethods::Get().ASurfaceTransaction_setFrameTimelineFn(
+ transaction_, vsync_id);
+}
+
void SurfaceControl::Transaction::SetOpaque(const Surface& surface,
bool opaque) {
int8_t transparency = opaque ? ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE
@@ -607,7 +810,11 @@
void SurfaceControl::Transaction::SetColorSpace(
const Surface& surface,
- const gfx::ColorSpace& color_space) {
+ const gfx::ColorSpace& color_space,
+ const absl::optional<HDRMetadata>& metadata) {
+ // Metadata shouldn't exist for SDR color spaces.
+ DCHECK(!metadata || color_space.IsHDR());
+
auto data_space = ColorSpaceToADataSpace(color_space);
// Log the data space in crash keys for debugging crbug.com/997592.
@@ -619,6 +826,59 @@
SurfaceControlMethods::Get().ASurfaceTransaction_setBufferDataSpaceFn(
transaction_, surface.surface(), data_space);
+
+ const bool extended_range =
+ (data_space & DataSpace::RANGE_MASK) == DataSpace::RANGE_EXTENDED;
+
+ // Set the HDR metadata for not extended SRGB case.
+ if (metadata && !extended_range) {
+ AHdrMetadata_cta861_3 cta861_3 = {
+ .maxContentLightLevel =
+ static_cast<float>(metadata->max_content_light_level),
+ .maxFrameAverageLightLevel =
+ static_cast<float>(metadata->max_frame_average_light_level)};
+
+ const auto& primaries = metadata->color_volume_metadata.primaries;
+ AHdrMetadata_smpte2086 smpte2086 = {
+ .displayPrimaryRed = {.x = primaries.fRX, .y = primaries.fRY},
+ .displayPrimaryGreen = {.x = primaries.fGX, .y = primaries.fGY},
+ .displayPrimaryBlue = {.x = primaries.fBX, .y = primaries.fBY},
+ .whitePoint = {.x = primaries.fWX, .y = primaries.fWY},
+ .maxLuminance = metadata->color_volume_metadata.luminance_max,
+ .minLuminance = metadata->color_volume_metadata.luminance_min};
+
+ SurfaceControlMethods::Get().ASurfaceTransaction_setHdrMetadata_cta861_3Fn(
+ transaction_, surface.surface(), &cta861_3);
+ SurfaceControlMethods::Get().ASurfaceTransaction_setHdrMetadata_smpte2086Fn(
+ transaction_, surface.surface(), &smpte2086);
+ } else {
+ SurfaceControlMethods::Get().ASurfaceTransaction_setHdrMetadata_cta861_3Fn(
+ transaction_, surface.surface(), nullptr);
+ SurfaceControlMethods::Get().ASurfaceTransaction_setHdrMetadata_smpte2086Fn(
+ transaction_, surface.surface(), nullptr);
+ }
+
+ // Set brightness points for extended range.
+ if (extended_range) {
+ CHECK(metadata);
+ CHECK(metadata->extended_range_brightness);
+ CHECK(SurfaceControlMethods::Get()
+ .ASurfaceTransaction_setExtendedRangeBrightnessFn);
+ SurfaceControlMethods::Get()
+ .ASurfaceTransaction_setExtendedRangeBrightnessFn(
+ transaction_, surface.surface(),
+ metadata->extended_range_brightness->current_buffer_ratio,
+ metadata->extended_range_brightness->desired_ratio);
+ } else {
+ // If extended range brightness is supported, we need reset it to default
+ // values.
+ if (SurfaceControlMethods::Get()
+ .ASurfaceTransaction_setExtendedRangeBrightnessFn) {
+ SurfaceControlMethods::Get()
+ .ASurfaceTransaction_setExtendedRangeBrightnessFn(
+ transaction_, surface.surface(), 1.0f, 1.0f);
+ }
+ }
}
void SurfaceControl::Transaction::SetFrameRate(const Surface& surface,
@@ -663,10 +923,12 @@
PrepareCallbacks();
SurfaceControlMethods::Get().ASurfaceTransaction_applyFn(transaction_);
+ need_to_apply_ = false;
}
ASurfaceTransaction* SurfaceControl::Transaction::GetTransaction() {
PrepareCallbacks();
+ need_to_apply_ = false;
return transaction_;
}
@@ -678,6 +940,9 @@
SurfaceControlMethods::Get().ASurfaceTransaction_setOnCommitFn(
transaction_, ack_ctx, &OnTransactiOnCommittedOnAnyThread);
+ // setOnCommit and setOnComplete increase ref count of SurfaceControl and
+ // Apply() is required to decrease the ref count.
+ need_to_apply_ = true;
}
if (on_complete_cb_) {
@@ -685,9 +950,26 @@
ack_ctx->callback = std::move(on_complete_cb_);
ack_ctx->id = id_;
+ bool dump = false;
+ {
+ base::AutoLock lock(GetGlobalLock());
+ auto result = GetGlobalPendingCompleteCallbackIds().insert(id_);
+ dump = !result.second;
+ }
+ if (dump) {
+ base::debug::DumpWithoutCrashing(base::Location::Current(),
+ base::Days(1));
+ }
SurfaceControlMethods::Get().ASurfaceTransaction_setOnCompleteFn(
transaction_, ack_ctx, &OnTransactionCompletedOnAnyThread);
+ need_to_apply_ = true;
}
}
+void SurfaceControl::Transaction::SetEnableBackPressure(const Surface& surface,
+ bool enable) {
+ SurfaceControlMethods::Get().ASurfaceTransaction_setEnableBackPressureFn(
+ transaction_, surface.surface(), enable);
+}
+
} // namespace gfx
diff --git a/ui/gfx/android/android_surface_control_compat.h b/ui/gfx/android/android_surface_control_compat.h
index d5eee6f..918f8c5 100644
--- a/ui/gfx/android/android_surface_control_compat.h
+++ b/ui/gfx/android/android_surface_control_compat.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,11 +11,17 @@
#include <memory>
#include <vector>
+#include "base/android/scoped_java_ref.h"
#include "base/files/scoped_file.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ptr_exclusion.h"
#include "base/memory/ref_counted.h"
-#include "base/single_thread_task_runner.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/time/time.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/gfx_export.h"
+#include "ui/gfx/hdr_metadata.h"
#include "ui/gfx/overlay_transform.h"
extern "C" {
@@ -51,6 +57,15 @@
// Returns true if OnCommit callback is supported.
static bool SupportsOnCommit();
+ // Returns true if tagging a transaction with vsync id is supported.
+ static GFX_EXPORT bool SupportsSetFrameTimeline();
+
+ // Returns true if APIs to convert Java SurfaceControl to ASurfaceControl.
+ static GFX_EXPORT bool SupportsSurfacelessControl();
+
+ // Returns true if API to enable back pressure is supported.
+ static GFX_EXPORT bool SupportsSetEnableBackPressure();
+
// Applies transaction. Used to emulate webview functor interface, where we
// pass raw ASurfaceTransaction object. For use inside Chromium use
// Transaction class below instead.
@@ -67,6 +82,8 @@
Surface();
Surface(const Surface& parent, const char* name);
Surface(ANativeWindow* parent, const char* name);
+ Surface(JNIEnv* env,
+ const base::android::JavaRef<jobject>& j_surface_control);
Surface(const Surface&) = delete;
Surface& operator=(const Surface&) = delete;
@@ -77,8 +94,8 @@
friend class base::RefCounted<Surface>;
~Surface();
- ASurfaceControl* surface_ = nullptr;
- ASurfaceControl* owned_surface_ = nullptr;
+ raw_ptr<ASurfaceControl> surface_ = nullptr;
+ raw_ptr<ASurfaceControl> owned_surface_ = nullptr;
};
struct GFX_EXPORT SurfaceStats {
@@ -88,7 +105,7 @@
SurfaceStats(SurfaceStats&& other);
SurfaceStats& operator=(SurfaceStats&& other);
- ASurfaceControl* surface = nullptr;
+ raw_ptr<ASurfaceControl> surface = nullptr;
// The fence which is signaled when the reads for the previous buffer for
// the given |surface| are finished.
@@ -138,12 +155,15 @@
void SetOpaque(const Surface& surface, bool opaque);
void SetDamageRect(const Surface& surface, const gfx::Rect& rect);
void SetColorSpace(const Surface& surface,
- const gfx::ColorSpace& color_space);
+ const gfx::ColorSpace& color_space,
+ const absl::optional<HDRMetadata>& metadata);
void SetFrameRate(const Surface& surface, float frame_rate);
void SetParent(const Surface& surface, Surface* new_parent);
void SetPosition(const Surface& surface, const gfx::Point& position);
void SetScale(const Surface& surface, float sx, float sy);
void SetCrop(const Surface& surface, const gfx::Rect& rect);
+ void SetFrameTimelineId(int64_t vsync_id);
+ void SetEnableBackPressure(const Surface& surface, bool enable);
// Sets the callback which will be dispatched when the transaction is acked
// by the framework.
@@ -159,15 +179,21 @@
scoped_refptr<base::SingleThreadTaskRunner> task_runner);
void Apply();
+ // Caller(e.g.,WebView) must call ASurfaceTransaction_apply(), otherwise
+ // SurfaceControl leaks.
ASurfaceTransaction* GetTransaction();
private:
void PrepareCallbacks();
+ void DestroyIfNeeded();
int id_;
- ASurfaceTransaction* transaction_;
+ // This field is not a raw_ptr<> because it was filtered by the rewriter
+ // for: #union
+ RAW_PTR_EXCLUSION ASurfaceTransaction* transaction_;
OnCommitCb on_commit_cb_;
OnCompleteCb on_complete_cb_;
+ bool need_to_apply_ = false;
};
};
} // namespace gfx
diff --git a/ui/gfx/android/android_surface_control_compat_unittest.cc b/ui/gfx/android/android_surface_control_compat_unittest.cc
index fd7d181..8c45e24 100644
--- a/ui/gfx/android/android_surface_control_compat_unittest.cc
+++ b/ui/gfx/android/android_surface_control_compat_unittest.cc
@@ -1,13 +1,14 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/android/android_surface_control_compat.h"
-#include "base/callback.h"
+#include "base/functional/callback.h"
+#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
+#include "base/task/single_thread_task_runner.h"
#include "base/test/task_environment.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace gfx {
@@ -24,8 +25,8 @@
CallbackContext(bool* called, bool* destroyed)
: called(called), destroyed(destroyed) {}
~CallbackContext() { *destroyed = true; }
- bool* called;
- bool* destroyed;
+ raw_ptr<bool> called;
+ raw_ptr<bool> destroyed;
};
SurfaceControl::Transaction::OnCompleteCb CreateOnCompleteCb(
@@ -52,8 +53,8 @@
void RunRemainingTasks() {
base::RunLoop runloop;
- base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
- runloop.QuitClosure());
+ base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+ FROM_HERE, runloop.QuitClosure());
runloop.Run();
}
@@ -69,10 +70,10 @@
gfx::SurfaceControl::Transaction transaction;
transaction.SetOnCompleteCb(
CreateOnCompleteCb(&on_complete_called, &on_complete_destroyed),
- base::ThreadTaskRunnerHandle::Get());
+ base::SingleThreadTaskRunner::GetCurrentDefault());
transaction.SetOnCommitCb(
CreateOnCommitCb(&on_commit_called, &on_commit_destroyed),
- base::ThreadTaskRunnerHandle::Get());
+ base::SingleThreadTaskRunner::GetCurrentDefault());
// Nothing should have been called yet.
EXPECT_FALSE(on_complete_called);
@@ -100,10 +101,10 @@
SurfaceControl::Transaction transaction;
transaction.SetOnCompleteCb(
CreateOnCompleteCb(&on_complete_called, &on_complete_destroyed),
- base::ThreadTaskRunnerHandle::Get());
+ base::SingleThreadTaskRunner::GetCurrentDefault());
transaction.SetOnCommitCb(
CreateOnCommitCb(&on_commit_called, &on_commit_destroyed),
- base::ThreadTaskRunnerHandle::Get());
+ base::SingleThreadTaskRunner::GetCurrentDefault());
// Nothing should have been called yet.
EXPECT_FALSE(on_complete_called);
@@ -127,10 +128,10 @@
gfx::SurfaceControl::Transaction transaction;
transaction.SetOnCompleteCb(
CreateOnCompleteCb(&on_complete_called, &on_complete_destroyed),
- base::ThreadTaskRunnerHandle::Get());
+ base::SingleThreadTaskRunner::GetCurrentDefault());
transaction.SetOnCommitCb(
CreateOnCommitCb(&on_commit_called, &on_commit_destroyed),
- base::ThreadTaskRunnerHandle::Get());
+ base::SingleThreadTaskRunner::GetCurrentDefault());
// Nothing should have been called yet.
EXPECT_FALSE(on_complete_called);
diff --git a/ui/gfx/android/java_bitmap.cc b/ui/gfx/android/java_bitmap.cc
index e107a55..0b232d4 100644
--- a/ui/gfx/android/java_bitmap.cc
+++ b/ui/gfx/android/java_bitmap.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,6 +9,7 @@
#include "base/android/jni_string.h"
#include "base/bits.h"
#include "base/check_op.h"
+#include "base/debug/crash_logging.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "ui/gfx/geometry/size.h"
@@ -48,6 +49,8 @@
return kRGB_565_SkColorType;
case BITMAP_FORMAT_NO_CONFIG:
default:
+ SCOPED_CRASH_KEY_NUMBER("gfx", "bitmap_format",
+ static_cast<int>(bitmap_format));
CHECK_NE(bitmap_format, bitmap_format);
return kUnknown_SkColorType;
}
@@ -130,7 +133,7 @@
// compositor relies on this.
SkPixmap src = WrapJavaBitmapAsPixmap(jbitmap);
const size_t min_row_bytes = src.info().minRowBytes();
- const size_t row_bytes = base::bits::AlignUp(min_row_bytes, 4u);
+ const size_t row_bytes = base::bits::AlignUp(min_row_bytes, size_t{4});
SkBitmap skbitmap;
skbitmap.allocPixels(src.info(), row_bytes);
diff --git a/ui/gfx/android/java_bitmap.h b/ui/gfx/android/java_bitmap.h
index 72ec80b..ade129e 100644
--- a/ui/gfx/android/java_bitmap.h
+++ b/ui/gfx/android/java_bitmap.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,7 +9,7 @@
#include <stdint.h>
#include "base/android/scoped_java_ref.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr_exclusion.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gfx_export.h"
@@ -49,7 +49,9 @@
private:
base::android::ScopedJavaGlobalRef<jobject> bitmap_;
- void* pixels_;
+ // This field is not a raw_ptr<> because it was filtered by the rewriter for:
+ // #addr-of
+ RAW_PTR_EXCLUSION void* pixels_;
gfx::Size size_;
BitmapFormat format_;
uint32_t bytes_per_row_;
diff --git a/ui/gfx/android/view_configuration.cc b/ui/gfx/android/view_configuration.cc
index 6397809..faf905e 100644
--- a/ui/gfx/android/view_configuration.cc
+++ b/ui/gfx/android/view_configuration.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,7 +6,6 @@
#include "base/android/jni_android.h"
#include "base/lazy_instance.h"
-#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "ui/gfx/gfx_jni_headers/ViewConfigurationHelper_jni.h"
diff --git a/ui/gfx/android/view_configuration.h b/ui/gfx/android/view_configuration.h
index e7353de..9b5c95e 100644
--- a/ui/gfx/android/view_configuration.h
+++ b/ui/gfx/android/view_configuration.h
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/BUILD.gn b/ui/gfx/animation/BUILD.gn
index 7876107..9dabaac 100644
--- a/ui/gfx/animation/BUILD.gn
+++ b/ui/gfx/animation/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
+# Copyright 2017 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -45,12 +45,8 @@
sources += [ "animation_win.cc" ]
}
- if (is_linux || is_chromeos_lacros) {
- sources += [
- "animation_linux.cc",
- "animation_settings_provider_linux.cc",
- "animation_settings_provider_linux.h",
- ]
+ if (is_linux) {
+ sources += [ "animation_linux.cc" ]
}
if (!is_android) {
@@ -84,5 +80,9 @@
deps += [ "//ui/gfx:gfx_jni_headers" ]
}
+ if (is_linux) {
+ deps += [ "//ui/linux:linux_ui" ]
+ }
+
defines = [ "ANIMATION_IMPLEMENTATION" ]
}
diff --git a/ui/gfx/animation/animation.cc b/ui/gfx/animation/animation.cc
index c07fb28..ddf6b17 100644
--- a/ui/gfx/animation/animation.cc
+++ b/ui/gfx/animation/animation.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -82,8 +82,8 @@
gfx::Rect Animation::CurrentValueBetween(const gfx::Rect& start_bounds,
const gfx::Rect& target_bounds) const {
- return Tween::RectValueBetween(
- GetCurrentValue(), start_bounds, target_bounds);
+ return Tween::RectValueBetween(GetCurrentValue(), start_bounds,
+ target_bounds);
}
void Animation::SetContainer(AnimationContainer* container) {
@@ -112,8 +112,8 @@
RichAnimationRenderMode::FORCE_ENABLED;
}
-#if defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_IOS) || \
- defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_IOS) || \
+ BUILDFLAG(IS_FUCHSIA)
// static
bool Animation::ShouldRenderRichAnimationImpl() {
return true;
@@ -126,7 +126,7 @@
// Defined in platform specific files for Windows and OSX and Linux.
}
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// static
void Animation::UpdatePrefersReducedMotion() {
// prefers_reduced_motion_ should only be modified on the UI thread.
@@ -136,9 +136,9 @@
// experience for users on systems that don't have APIs for reduced motion.
prefers_reduced_motion_ = false;
}
-#endif // !defined(OS_ANDROID)
-#endif // defined(OS_ANDROID) || BUILDFLAG(IS_CHROMEOS_ASH) || defined(OS_IOS)
- // || defined(OS_FUCHSIA)
+#endif // !BUILDFLAG(IS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS) ||
+ // BUILDFLAG(IS_IOS) || BUILDFLAG(IS_FUCHSIA)
// static
bool Animation::PrefersReducedMotion() {
diff --git a/ui/gfx/animation/animation.h b/ui/gfx/animation/animation.h
index e665d1f..569c395 100644
--- a/ui/gfx/animation/animation.h
+++ b/ui/gfx/animation/animation.h
@@ -1,13 +1,12 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_ANIMATION_ANIMATION_H_
#define UI_GFX_ANIMATION_ANIMATION_H_
-#include "base/compiler_specific.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/scoped_refptr.h"
#include "base/time/time.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/animation/animation_container_element.h"
@@ -129,7 +128,7 @@
bool is_animating_;
// Our delegate; may be null.
- AnimationDelegate* delegate_;
+ raw_ptr<AnimationDelegate, DanglingUntriaged> delegate_;
// Container we're in. If non-null we're animating.
scoped_refptr<AnimationContainer> container_;
diff --git a/ui/gfx/animation/animation_android.cc b/ui/gfx/animation/animation_android.cc
index 1637e2d..01f728d 100644
--- a/ui/gfx/animation/animation_android.cc
+++ b/ui/gfx/animation/animation_android.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/animation_container.cc b/ui/gfx/animation/animation_container.cc
index dbfbd6b..f7bf656 100644
--- a/ui/gfx/animation/animation_container.cc
+++ b/ui/gfx/animation/animation_container.cc
@@ -1,10 +1,10 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/animation/animation_container.h"
-#include "base/bind.h"
+#include "base/functional/bind.h"
#include "ui/gfx/animation/animation_container_element.h"
#include "ui/gfx/animation/animation_container_observer.h"
diff --git a/ui/gfx/animation/animation_container.h b/ui/gfx/animation/animation_container.h
index fc80028..484e46b 100644
--- a/ui/gfx/animation/animation_container.h
+++ b/ui/gfx/animation/animation_container.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,7 +9,7 @@
#include <utility>
#include "base/containers/flat_set.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "ui/gfx/animation/animation_export.h"
@@ -114,7 +114,7 @@
AnimationRunner::CreateDefaultAnimationRunner();
bool has_custom_animation_runner_ = false;
- AnimationContainerObserver* observer_ = nullptr;
+ raw_ptr<AnimationContainerObserver> observer_ = nullptr;
};
} // namespace gfx
diff --git a/ui/gfx/animation/animation_container_element.h b/ui/gfx/animation/animation_container_element.h
index 6e39ef4..108d6c1 100644
--- a/ui/gfx/animation/animation_container_element.h
+++ b/ui/gfx/animation/animation_container_element.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/animation_container_observer.h b/ui/gfx/animation/animation_container_observer.h
index 77d9cb4..7ce8902 100644
--- a/ui/gfx/animation/animation_container_observer.h
+++ b/ui/gfx/animation/animation_container_observer.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/animation_container_unittest.cc b/ui/gfx/animation/animation_container_unittest.cc
index 9322e21..b3a2d0b 100644
--- a/ui/gfx/animation/animation_container_unittest.cc
+++ b/ui/gfx/animation/animation_container_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,7 +6,6 @@
#include <memory>
-#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/ui/gfx/animation/animation_delegate.h b/ui/gfx/animation/animation_delegate.h
index b582d16..42c0b3d 100644
--- a/ui/gfx/animation/animation_delegate.h
+++ b/ui/gfx/animation/animation_delegate.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/animation_delegate_notifier.h b/ui/gfx/animation/animation_delegate_notifier.h
index 7983a70..e74f374 100644
--- a/ui/gfx/animation/animation_delegate_notifier.h
+++ b/ui/gfx/animation/animation_delegate_notifier.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,7 @@
#define UI_GFX_ANIMATION_ANIMATION_DELEGATE_NOTIFIER_H_
#include "base/check.h"
+#include "base/memory/raw_ptr.h"
#include "ui/gfx/animation/animation_delegate.h"
namespace gfx {
@@ -47,7 +48,7 @@
}
private:
- gfx::AnimationDelegate* const owner_;
+ const raw_ptr<gfx::AnimationDelegate> owner_;
};
} // namespace gfx
diff --git a/ui/gfx/animation/animation_export.h b/ui/gfx/animation/animation_export.h
index 0b03b1b..586d5d8 100644
--- a/ui/gfx/animation/animation_export.h
+++ b/ui/gfx/animation/animation_export.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/animation_linux.cc b/ui/gfx/animation/animation_linux.cc
index 0bcce53..8b3afc6 100644
--- a/ui/gfx/animation/animation_linux.cc
+++ b/ui/gfx/animation/animation_linux.cc
@@ -1,20 +1,20 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/animation/animation.h"
-#include "ui/gfx/animation/animation_settings_provider_linux.h"
+#include "ui/linux/linux_ui.h"
namespace gfx {
namespace {
-// GTK only has a global setting for whether animations should be enabled. So
-// use it for all of the specific settings that Chrome needs.
+// Linux toolkits only have a global setting for whether animations should be
+// enabled. So use it for all of the specific settings that Chrome needs.
bool AnimationsEnabled() {
- auto* provider = AnimationSettingsProviderLinux::GetInstance();
- return !provider || provider->AnimationsEnabled();
+ auto* linux_ui = ui::LinuxUi::instance();
+ return !linux_ui || linux_ui->AnimationsEnabled();
}
} // namespace
diff --git a/ui/gfx/animation/animation_mac.mm b/ui/gfx/animation/animation_mac.mm
index 175ceff..d1be200 100644
--- a/ui/gfx/animation/animation_mac.mm
+++ b/ui/gfx/animation/animation_mac.mm
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,11 +9,6 @@
#include "base/mac/mac_util.h"
#include "base/task/current_thread.h"
-// Only available since 10.12.
-@interface NSWorkspace (AvailableSinceSierra)
-@property(readonly) BOOL accessibilityDisplayShouldReduceMotion;
-@end
-
namespace gfx {
// static
@@ -41,14 +36,8 @@
// prefers_reduced_motion_ should only be modified on the UI thread.
// TODO(crbug.com/927163): DCHECK this assertion once tests are well-behaved.
- // We default to assuming that animations are enabled, to avoid impacting the
- // experience for users on pre-10.12 systems.
- prefers_reduced_motion_ = false;
- SEL sel = @selector(accessibilityDisplayShouldReduceMotion);
- if ([[NSWorkspace sharedWorkspace] respondsToSelector:sel]) {
- prefers_reduced_motion_ =
- [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldReduceMotion];
- }
+ prefers_reduced_motion_ =
+ [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldReduceMotion];
}
} // namespace gfx
diff --git a/ui/gfx/animation/animation_runner.cc b/ui/gfx/animation/animation_runner.cc
index eebf9e4..cc9d52b 100644
--- a/ui/gfx/animation/animation_runner.cc
+++ b/ui/gfx/animation/animation_runner.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/animation_runner.h b/ui/gfx/animation/animation_runner.h
index 988bc6c..daceb3c 100644
--- a/ui/gfx/animation/animation_runner.h
+++ b/ui/gfx/animation/animation_runner.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,7 +7,7 @@
#include <memory>
-#include "base/callback.h"
+#include "base/functional/callback.h"
#include "base/time/time.h"
#include "ui/gfx/animation/animation_export.h"
diff --git a/ui/gfx/animation/animation_runner_unittest.cc b/ui/gfx/animation/animation_runner_unittest.cc
index 632740e..a214ba4 100644
--- a/ui/gfx/animation/animation_runner_unittest.cc
+++ b/ui/gfx/animation/animation_runner_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/animation_settings_provider_linux.cc b/ui/gfx/animation/animation_settings_provider_linux.cc
deleted file mode 100644
index e4d4c6c..0000000
--- a/ui/gfx/animation/animation_settings_provider_linux.cc
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/animation/animation_settings_provider_linux.h"
-
-#include "base/check_op.h"
-
-namespace gfx {
-
-// static
-AnimationSettingsProviderLinux* AnimationSettingsProviderLinux::instance_ =
- nullptr;
-
-// static
-AnimationSettingsProviderLinux* AnimationSettingsProviderLinux::GetInstance() {
- return instance_;
-}
-
-AnimationSettingsProviderLinux::AnimationSettingsProviderLinux() {
- DCHECK(!instance_);
- instance_ = this;
-}
-
-AnimationSettingsProviderLinux::~AnimationSettingsProviderLinux() {
- DCHECK_EQ(instance_, this);
- instance_ = nullptr;
-}
-
-} // namespace gfx
diff --git a/ui/gfx/animation/animation_settings_provider_linux.h b/ui/gfx/animation/animation_settings_provider_linux.h
deleted file mode 100644
index 0deac36..0000000
--- a/ui/gfx/animation/animation_settings_provider_linux.h
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_ANIMATION_ANIMATION_SETTINGS_PROVIDER_LINUX_H_
-#define UI_GFX_ANIMATION_ANIMATION_SETTINGS_PROVIDER_LINUX_H_
-
-#include "base/macros.h"
-#include "ui/gfx/animation/animation_export.h"
-
-namespace gfx {
-
-class ANIMATION_EXPORT AnimationSettingsProviderLinux {
- public:
- AnimationSettingsProviderLinux(const AnimationSettingsProviderLinux&) =
- delete;
- AnimationSettingsProviderLinux& operator=(
- const AnimationSettingsProviderLinux&) = delete;
-
- virtual ~AnimationSettingsProviderLinux();
-
- // Indicates if animations are enabled by the toolkit.
- virtual bool AnimationsEnabled() const = 0;
-
- static AnimationSettingsProviderLinux* GetInstance();
-
- protected:
- AnimationSettingsProviderLinux();
-
- private:
- static AnimationSettingsProviderLinux* instance_;
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_ANIMATION_ANIMATION_SETTINGS_PROVIDER_LINUX_H_
diff --git a/ui/gfx/animation/animation_test_api.cc b/ui/gfx/animation/animation_test_api.cc
index 365990c..aa21a6d 100644
--- a/ui/gfx/animation/animation_test_api.cc
+++ b/ui/gfx/animation/animation_test_api.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/animation_test_api.h b/ui/gfx/animation/animation_test_api.h
index 0794046..fbba6b6 100644
--- a/ui/gfx/animation/animation_test_api.h
+++ b/ui/gfx/animation/animation_test_api.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,7 +8,7 @@
#include <memory>
#include "base/auto_reset.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
#include "ui/gfx/animation/animation.h"
#include "ui/gfx/animation/animation_container.h"
#include "ui/gfx/animation/animation_export.h"
@@ -37,7 +37,7 @@
void Step(base::TimeTicks ticks);
private:
- Animation* animation_;
+ raw_ptr<Animation> animation_;
};
// For manual animation time control in tests. Creating this object will
@@ -53,7 +53,7 @@
void IncrementTime(base::TimeDelta delta);
private:
- AnimationContainer* container_;
+ raw_ptr<AnimationContainer> container_;
};
} // namespace gfx
diff --git a/ui/gfx/animation/animation_unittest.cc b/ui/gfx/animation/animation_unittest.cc
index 130390d..e47c0f6 100644
--- a/ui/gfx/animation/animation_unittest.cc
+++ b/ui/gfx/animation/animation_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -12,7 +12,7 @@
#include "ui/gfx/animation/test_animation_delegate.h"
#include "ui/gfx/switches.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#endif
@@ -136,7 +136,7 @@
}
TEST_F(AnimationTest, ShouldRenderRichAnimation) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
BOOL result;
ASSERT_NE(0,
::SystemParametersInfo(SPI_GETCLIENTAREAANIMATION, 0, &result, 0));
diff --git a/ui/gfx/animation/animation_win.cc b/ui/gfx/animation/animation_win.cc
index c8fdc6d..284522a 100644
--- a/ui/gfx/animation/animation_win.cc
+++ b/ui/gfx/animation/animation_win.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/keyframe/BUILD.gn b/ui/gfx/animation/keyframe/BUILD.gn
index 85e2bef..2e621a8 100644
--- a/ui/gfx/animation/keyframe/BUILD.gn
+++ b/ui/gfx/animation/keyframe/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2021 The Chromium Authors. All rights reserved.
+# Copyright 2021 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -7,7 +7,6 @@
keyframe_animation_remove_configs = []
keyframe_animation_add_configs = [
"//build/config:precompiled_headers",
- "//build/config/compiler:noshadowing",
"//build/config/compiler:wexit_time_destructors",
]
diff --git a/ui/gfx/animation/keyframe/animation_curve.cc b/ui/gfx/animation/keyframe/animation_curve.cc
index 17fcc23..daa0225 100644
--- a/ui/gfx/animation/keyframe/animation_curve.cc
+++ b/ui/gfx/animation/keyframe/animation_curve.cc
@@ -1,10 +1,11 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/animation/keyframe/animation_curve.h"
#include "base/check.h"
+#include "ui/gfx/geometry/transform_operations.h"
namespace gfx {
diff --git a/ui/gfx/animation/keyframe/animation_curve.h b/ui/gfx/animation/keyframe/animation_curve.h
index 105c53e..1c068f4 100644
--- a/ui/gfx/animation/keyframe/animation_curve.h
+++ b/ui/gfx/animation/keyframe/animation_curve.h
@@ -1,4 +1,4 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,13 +7,13 @@
#include <memory>
+#include "base/memory/raw_ptr_exclusion.h"
#include "base/time/time.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/animation/keyframe/keyframe_animation_export.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/geometry/transform.h"
-#include "ui/gfx/geometry/transform_operations.h"
namespace gfx {
class TransformOperations;
@@ -61,6 +61,8 @@
virtual base::TimeDelta TickInterval() const;
};
+// |target_| field is not a raw_ptr<> because it was filtered by the rewriter
+// for: #constexpr-ctor-field-initializer, #macro
#define DECLARE_ANIMATION_CURVE_BODY(T, Name) \
public: \
static const Name##AnimationCurve* To##Name##AnimationCurve( \
@@ -77,15 +79,19 @@
virtual T GetValue(base::TimeDelta t) const = 0; \
void Tick(base::TimeDelta t, int property_id, \
gfx::KeyframeModel* keyframe_model) const override; \
- void set_target(Target* target) { target_ = target; } \
+ void set_target(Target* target) { \
+ target_ = target; \
+ } \
int Type() const override; \
const char* TypeName() const override; \
\
protected: \
- Target* target() const { return target_; } \
+ Target* target() const { \
+ return target_; \
+ } \
\
private: \
- Target* target_ = nullptr;
+ RAW_PTR_EXCLUSION Target* target_ = nullptr;
class GFX_KEYFRAME_ANIMATION_EXPORT ColorAnimationCurve
: public AnimationCurve {
diff --git a/ui/gfx/animation/keyframe/keyframe_animation_export.h b/ui/gfx/animation/keyframe/keyframe_animation_export.h
index db0f21e..518c84a 100644
--- a/ui/gfx/animation/keyframe/keyframe_animation_export.h
+++ b/ui/gfx/animation/keyframe/keyframe_animation_export.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/keyframe/keyframe_animation_unittest.cc b/ui/gfx/animation/keyframe/keyframe_animation_unittest.cc
index 90158df..fbd431f 100644
--- a/ui/gfx/animation/keyframe/keyframe_animation_unittest.cc
+++ b/ui/gfx/animation/keyframe/keyframe_animation_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,8 +9,7 @@
#include "ui/gfx/animation/keyframe/animation_curve.h"
#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
#include "ui/gfx/animation/keyframe/test/animation_utils.h"
-#include "ui/gfx/geometry/test/size_test_util.h"
-#include "ui/gfx/test/gfx_util.h"
+#include "ui/gfx/geometry/test/geometry_util.h"
namespace gfx {
@@ -545,7 +544,7 @@
animator.TransitionSizeTo(&target, start_time, kBoundsPropertyId, from, to);
- EXPECT_FLOAT_SIZE_EQ(from, target.size());
+ EXPECT_SIZEF_EQ(from, target.size());
animator.Tick(start_time);
// Scheduling a redundant, approximately equal transition should be ignored.
@@ -563,7 +562,7 @@
EXPECT_GT(to.height(), target.size().height());
animator.Tick(start_time + MicrosecondsToDelta(10000));
- EXPECT_FLOAT_SIZE_EQ(to, target.size());
+ EXPECT_SIZEF_EQ(to, target.size());
}
TEST(KeyframeAnimationTest, RetargetSizeTransition) {
@@ -588,7 +587,7 @@
EXPECT_EQ(from, target.size());
animator.Tick(start_time + MicrosecondsToDelta(5000));
- EXPECT_FLOAT_SIZE_EQ(SizeF(6, 12), target.size());
+ EXPECT_SIZEF_EQ(SizeF(6, 12), target.size());
SizeF new_to(600, 1200);
@@ -596,10 +595,10 @@
->Retarget(start_time + MicrosecondsToDelta(5000), kRectPropertyId,
new_to);
animator.Tick(start_time + MicrosecondsToDelta(5000));
- EXPECT_FLOAT_SIZE_EQ(SizeF(6, 12), target.size());
+ EXPECT_SIZEF_EQ(SizeF(6, 12), target.size());
animator.Tick(start_time + MicrosecondsToDelta(7500));
- EXPECT_FLOAT_SIZE_EQ(SizeF(303, 606), target.size());
+ EXPECT_SIZEF_EQ(SizeF(303, 606), target.size());
}
TEST(KeyframeAnimationTest, ReversedBoundsTransitions) {
@@ -617,7 +616,7 @@
animator.TransitionSizeTo(&target, start_time, kBoundsPropertyId, from, to);
- EXPECT_FLOAT_SIZE_EQ(from, target.size());
+ EXPECT_SIZEF_EQ(from, target.size());
animator.Tick(start_time);
animator.Tick(start_time + MicrosecondsToDelta(1000));
@@ -630,10 +629,10 @@
animator.TransitionSizeTo(&target, start_time + MicrosecondsToDelta(1000),
kBoundsPropertyId, target.size(), from);
animator.Tick(start_time + MicrosecondsToDelta(1000));
- EXPECT_FLOAT_SIZE_EQ(value_before_reversing, target.size());
+ EXPECT_SIZEF_EQ(value_before_reversing, target.size());
animator.Tick(start_time + MicrosecondsToDelta(2000));
- EXPECT_FLOAT_SIZE_EQ(from, target.size());
+ EXPECT_SIZEF_EQ(from, target.size());
}
TEST(KeyframeAnimationTest, BackgroundColorTransitions) {
diff --git a/ui/gfx/animation/keyframe/keyframe_effect.cc b/ui/gfx/animation/keyframe/keyframe_effect.cc
index 46304b1..e5e0f4e 100644
--- a/ui/gfx/animation/keyframe/keyframe_effect.cc
+++ b/ui/gfx/animation/keyframe/keyframe_effect.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/keyframe/keyframe_effect.h b/ui/gfx/animation/keyframe/keyframe_effect.h
index 818dce7..e4655bb 100644
--- a/ui/gfx/animation/keyframe/keyframe_effect.h
+++ b/ui/gfx/animation/keyframe/keyframe_effect.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,7 +9,6 @@
#include <set>
#include <vector>
-#include "base/macros.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/animation/keyframe/animation_curve.h"
#include "ui/gfx/animation/keyframe/keyframe_animation_export.h"
diff --git a/ui/gfx/animation/keyframe/keyframe_model.cc b/ui/gfx/animation/keyframe/keyframe_model.cc
index eaa8a86..0ffa309 100644
--- a/ui/gfx/animation/keyframe/keyframe_model.cc
+++ b/ui/gfx/animation/keyframe/keyframe_model.cc
@@ -1,12 +1,12 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/animation/keyframe/keyframe_model.h"
-#include "base/cxx17_backports.h"
#include "base/memory/ptr_util.h"
#include "base/notreached.h"
+#include "base/time/time.h"
namespace gfx {
namespace {
@@ -22,7 +22,7 @@
"ABORTED_BUT_NEEDS_COMPLETION"};
static_assert(static_cast<int>(KeyframeModel::LAST_RUN_STATE) + 1 ==
- base::size(s_runStateNames),
+ std::size(s_runStateNames),
"RunStateEnumSize should equal the number of elements in "
"s_runStateNames");
@@ -178,7 +178,7 @@
base::TimeDelta start_offset = curve_->Duration() * iteration_start_;
// Return start offset if we are before the start of the keyframe model
- if (active_time < base::TimeDelta())
+ if (active_time.is_negative())
return start_offset;
// Always return zero if we have no iterations.
if (!iterations_)
diff --git a/ui/gfx/animation/keyframe/keyframe_model.h b/ui/gfx/animation/keyframe/keyframe_model.h
index 3cb053b..3b9aefc 100644
--- a/ui/gfx/animation/keyframe/keyframe_model.h
+++ b/ui/gfx/animation/keyframe/keyframe_model.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,6 +7,7 @@
#include <string>
+#include "base/time/time.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/animation/keyframe/animation_curve.h"
#include "ui/gfx/animation/keyframe/keyframe_animation_export.h"
@@ -102,8 +103,9 @@
}
// This is the number of times that the keyframe model will play. If this
- // value is zero the keyframe model will not play. If it is negative, then
- // the keyframe model will loop indefinitely.
+ // value is zero or negative, the keyframe model will not play. If it is
+ // std::numeric_limits<double>::infinity(), then the keyframe model will loop
+ // indefinitely.
double iterations() const { return iterations_; }
void set_iterations(double n) { iterations_ = n; }
diff --git a/ui/gfx/animation/keyframe/keyframed_animation_curve-inl.h b/ui/gfx/animation/keyframe/keyframed_animation_curve-inl.h
index ac226f6..90fc97a 100644
--- a/ui/gfx/animation/keyframe/keyframed_animation_curve-inl.h
+++ b/ui/gfx/animation/keyframe/keyframed_animation_curve-inl.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/keyframe/keyframed_animation_curve.cc b/ui/gfx/animation/keyframe/keyframed_animation_curve.cc
index 3aba6cf..168ab31 100644
--- a/ui/gfx/animation/keyframe/keyframed_animation_curve.cc
+++ b/ui/gfx/animation/keyframe/keyframed_animation_curve.cc
@@ -1,4 +1,4 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/keyframe/keyframed_animation_curve.h b/ui/gfx/animation/keyframe/keyframed_animation_curve.h
index 9a292b5..3a54ddf 100644
--- a/ui/gfx/animation/keyframe/keyframed_animation_curve.h
+++ b/ui/gfx/animation/keyframe/keyframed_animation_curve.h
@@ -1,4 +1,4 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/keyframe/keyframed_animation_curve_unittest.cc b/ui/gfx/animation/keyframe/keyframed_animation_curve_unittest.cc
index 2153163..075b92f 100644
--- a/ui/gfx/animation/keyframe/keyframed_animation_curve_unittest.cc
+++ b/ui/gfx/animation/keyframe/keyframed_animation_curve_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,16 +9,16 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/geometry/box_f.h"
-#include "ui/gfx/geometry/test/transform_test_util.h"
+#include "ui/gfx/geometry/test/geometry_util.h"
#include "ui/gfx/geometry/transform_operations.h"
-#include "ui/gfx/test/gfx_util.h"
+#include "ui/gfx/test/sk_color_eq.h"
namespace gfx {
namespace {
void ExpectTranslateX(SkScalar translate_x,
const gfx::TransformOperations& operations) {
- EXPECT_FLOAT_EQ(translate_x, operations.Apply().matrix().get(0, 3));
+ EXPECT_FLOAT_EQ(translate_x, operations.Apply().rc(0, 3));
}
// Tests that a color animation with one keyframe works as expected.
@@ -265,8 +265,8 @@
// There is a discontinuity at 1. Any value between 4 and 6 is valid.
gfx::Transform value = curve->GetValue(base::Seconds(1.f)).Apply();
- EXPECT_GE(value.matrix().get(0, 3), 4.f);
- EXPECT_LE(value.matrix().get(0, 3), 6.f);
+ EXPECT_GE(value.rc(0, 3), 4.f);
+ EXPECT_LE(value.rc(0, 3), 6.f);
ExpectTranslateX(6.f, curve->GetValue(base::Seconds(1.5f)));
ExpectTranslateX(6.f, curve->GetValue(base::Seconds(2.f)));
@@ -276,7 +276,7 @@
// Tests that a discrete transform animation (e.g. where one or more keyframes
// is a non-invertible matrix) works as expected.
TEST(KeyframedAnimationCurveTest, DiscreteLinearTransformAnimation) {
- gfx::Transform non_invertible_matrix(0, 0, 0, 0, 0, 0);
+ auto non_invertible_matrix = gfx::Transform::MakeScale(0);
gfx::Transform identity_matrix;
std::unique_ptr<KeyframedTransformAnimationCurve> curve(
@@ -299,28 +299,28 @@
// Between 0 and 0.5 seconds, the first keyframe should be returned.
result = curve->GetValue(base::Seconds(0.01f));
- ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+ EXPECT_TRANSFORM_EQ(non_invertible_matrix, result.Apply());
result = curve->GetValue(base::Seconds(0.49f));
- ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+ EXPECT_TRANSFORM_EQ(non_invertible_matrix, result.Apply());
// Between 0.5 and 1.5 seconds, the middle keyframe should be returned.
result = curve->GetValue(base::Seconds(0.5f));
- ExpectTransformationMatrixEq(identity_matrix, result.Apply());
+ EXPECT_TRANSFORM_EQ(identity_matrix, result.Apply());
result = curve->GetValue(base::Seconds(1.49f));
- ExpectTransformationMatrixEq(identity_matrix, result.Apply());
+ EXPECT_TRANSFORM_EQ(identity_matrix, result.Apply());
// Between 1.5 and 2.0 seconds, the last keyframe should be returned.
result = curve->GetValue(base::Seconds(1.5f));
- ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+ EXPECT_TRANSFORM_EQ(non_invertible_matrix, result.Apply());
result = curve->GetValue(base::Seconds(2.0f));
- ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+ EXPECT_TRANSFORM_EQ(non_invertible_matrix, result.Apply());
}
TEST(KeyframedAnimationCurveTest, DiscreteCubicBezierTransformAnimation) {
- gfx::Transform non_invertible_matrix(0, 0, 0, 0, 0, 0);
+ auto non_invertible_matrix = gfx::Transform::MakeScale(0);
gfx::Transform identity_matrix;
std::unique_ptr<KeyframedTransformAnimationCurve> curve(
@@ -349,24 +349,24 @@
// Due to the cubic-bezier, the first keyframe is returned almost all the way
// to 1 second.
result = curve->GetValue(base::Seconds(0.01f));
- ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+ EXPECT_TRANSFORM_EQ(non_invertible_matrix, result.Apply());
result = curve->GetValue(base::Seconds(0.8f));
- ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+ EXPECT_TRANSFORM_EQ(non_invertible_matrix, result.Apply());
// Between ~0.85 and ~1.85 seconds, the middle keyframe should be returned.
result = curve->GetValue(base::Seconds(0.85f));
- ExpectTransformationMatrixEq(identity_matrix, result.Apply());
+ EXPECT_TRANSFORM_EQ(identity_matrix, result.Apply());
result = curve->GetValue(base::Seconds(1.8f));
- ExpectTransformationMatrixEq(identity_matrix, result.Apply());
+ EXPECT_TRANSFORM_EQ(identity_matrix, result.Apply());
// Finally the last keyframe only takes effect after ~1.85 seconds.
result = curve->GetValue(base::Seconds(1.85f));
- ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+ EXPECT_TRANSFORM_EQ(non_invertible_matrix, result.Apply());
result = curve->GetValue(base::Seconds(2.0f));
- ExpectTransformationMatrixEq(non_invertible_matrix, result.Apply());
+ EXPECT_TRANSFORM_EQ(non_invertible_matrix, result.Apply());
}
// Tests that the keyframes may be added out of order.
@@ -472,6 +472,27 @@
}
}
+// A jump_both steps function has 1 extra jump. Ensure that this doesn't
+// overflow when using the maximum number of steps. In this case, the steps
+// function should be effectively the same as linear.
+// crbug.com/1313399
+TEST(KeyframedAnimationCurveTest, StepsTimingFunctionMaxSteps) {
+ std::unique_ptr<KeyframedFloatAnimationCurve> curve(
+ KeyframedFloatAnimationCurve::Create());
+ const int num_steps = std::numeric_limits<int>::max();
+ curve->AddKeyframe(FloatKeyframe::Create(
+ base::TimeDelta(), 0.f,
+ StepsTimingFunction::Create(
+ num_steps, StepsTimingFunction::StepPosition::JUMP_BOTH)));
+ curve->AddKeyframe(FloatKeyframe::Create(base::Seconds(1.0), 1.f, nullptr));
+
+ for (int i = 0; i <= 100; i++) {
+ const float value = 0.001f * i;
+ const base::TimeDelta time = base::Seconds(value);
+ EXPECT_NEAR(value, curve->GetValue(time), 0.0001);
+ }
+}
+
// Tests that maximum animation scale is computed as expected.
TEST(KeyframedAnimationCurveTest, MaximumScale) {
std::unique_ptr<KeyframedTransformAnimationCurve> curve(
diff --git a/ui/gfx/animation/keyframe/target_property.h b/ui/gfx/animation/keyframe/target_property.h
index 1c76ab4..7a57c30 100644
--- a/ui/gfx/animation/keyframe/target_property.h
+++ b/ui/gfx/animation/keyframe/target_property.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/keyframe/test/animation_utils.cc b/ui/gfx/animation/keyframe/test/animation_utils.cc
index d0b7098..640442e 100644
--- a/ui/gfx/animation/keyframe/test/animation_utils.cc
+++ b/ui/gfx/animation/keyframe/test/animation_utils.cc
@@ -1,9 +1,10 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/animation/keyframe/test/animation_utils.h"
+#include "base/time/time.h"
#include "ui/gfx/animation/keyframe/keyframed_animation_curve.h"
namespace gfx {
diff --git a/ui/gfx/animation/keyframe/test/animation_utils.h b/ui/gfx/animation/keyframe/test/animation_utils.h
index 355c3ed..94a8161 100644
--- a/ui/gfx/animation/keyframe/test/animation_utils.h
+++ b/ui/gfx/animation/keyframe/test/animation_utils.h
@@ -1,5 +1,4 @@
-
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/keyframe/timing_function.cc b/ui/gfx/animation/keyframe/timing_function.cc
index 9650a50..73e2835 100644
--- a/ui/gfx/animation/keyframe/timing_function.cc
+++ b/ui/gfx/animation/keyframe/timing_function.cc
@@ -1,9 +1,10 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/animation/keyframe/timing_function.h"
+#include <algorithm>
#include <cmath>
#include <memory>
@@ -125,7 +126,7 @@
return steps_;
case StepPosition::JUMP_BOTH:
- return steps_ + 1;
+ return steps_ < std::numeric_limits<int>::max() ? steps_ + 1 : steps_;
case StepPosition::JUMP_NONE:
DCHECK_GT(steps_, 1);
@@ -155,13 +156,27 @@
}
}
+LinearTimingFunction::LinearTimingFunction() = default;
+
+LinearTimingFunction::LinearTimingFunction(
+ std::vector<LinearEasingPoint> points)
+ : points_(std::move(points)) {}
+
+LinearTimingFunction::~LinearTimingFunction() = default;
+
+LinearTimingFunction::LinearTimingFunction(const LinearTimingFunction& other) {
+ points_ = other.points_;
+}
+
std::unique_ptr<LinearTimingFunction> LinearTimingFunction::Create() {
return base::WrapUnique(new LinearTimingFunction());
}
-LinearTimingFunction::LinearTimingFunction() = default;
-
-LinearTimingFunction::~LinearTimingFunction() = default;
+std::unique_ptr<LinearTimingFunction> LinearTimingFunction::Create(
+ std::vector<LinearEasingPoint> points) {
+ DCHECK(points.size() >= 2);
+ return base::WrapUnique(new LinearTimingFunction(std::move(points)));
+}
TimingFunction::Type LinearTimingFunction::GetType() const {
return Type::LINEAR;
@@ -175,8 +190,46 @@
return 0;
}
-double LinearTimingFunction::GetValue(double t) const {
- return t;
+double LinearTimingFunction::GetValue(double input_progress) const {
+ if (IsTrivial()) {
+ return input_progress;
+ }
+ // https://w3c.github.io/csswg-drafts/css-easing/#linear-easing-function-output
+ // 1. Let points be linearEasingFunction’s points.
+ // 2. Let pointAIndex be index of the last item in points with an input
+ // less than or equal to inputProgress, or 0 if there is no match.
+ auto it = std::upper_bound(points_.cbegin(), points_.cend(), input_progress,
+ [](double progress, const auto& point) {
+ return 100 * progress < point.input;
+ });
+ it = it == points_.cend() ? std::prev(it) : it;
+ auto point_a = it == points_.cbegin() ? it : std::prev(it);
+ // 3. If pointAIndex is equal to points size minus 1, decrement pointAIndex
+ // by 1.
+ point_a = std::next(point_a) == points_.cend() ? std::prev(point_a) : point_a;
+ // 4. Let pointA be points[pointAIndex].
+ // 5. Let pointB be points[pointAIndex + 1].
+ const auto& point_b = std::next(point_a);
+ // 6. If pointA’s input is equal to pointB’s input, return pointB’s output.
+ if (point_a->input == point_b->input) {
+ return point_b->output;
+ }
+ // 7. Let progressFromPointA be inputProgress minus pointA’s input.
+ const double progress_from_point_a = input_progress - point_a->input / 100;
+ // 8. Let pointInputRange be pointB’s input minus pointA’s input.
+ const double point_input_range = (point_b->input - point_a->input) / 100;
+ // 9. Let progressBetweenPoints be progressFromPointA divided by
+ // pointInputRange.
+ const double progress_between_points =
+ progress_from_point_a / point_input_range;
+ // 10. Let pointOutputRange be pointB’s output minus pointA’s output.
+ const double point_output_range = point_b->output - point_a->output;
+ // 11. Let outputFromLastPoint be progressBetweenPoints multiplied by
+ // pointOutputRange.
+ const double output_from_last_point =
+ progress_between_points * point_output_range;
+ // 12. Return pointA’s output plus outputFromLastPoint.
+ return point_a->output + output_from_last_point;
}
} // namespace gfx
diff --git a/ui/gfx/animation/keyframe/timing_function.h b/ui/gfx/animation/keyframe/timing_function.h
index 7ce7133..753e844 100644
--- a/ui/gfx/animation/keyframe/timing_function.h
+++ b/ui/gfx/animation/keyframe/timing_function.h
@@ -1,4 +1,4 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,7 @@
#define UI_GFX_ANIMATION_KEYFRAME_TIMING_FUNCTION_H_
#include <memory>
+#include <vector>
#include "ui/gfx/animation/keyframe/keyframe_animation_export.h"
#include "ui/gfx/geometry/cubic_bezier.h"
@@ -122,10 +123,32 @@
StepPosition step_position_;
};
+struct GFX_KEYFRAME_ANIMATION_EXPORT LinearEasingPoint {
+ double input;
+ double output;
+
+ LinearEasingPoint() = default;
+ LinearEasingPoint(double input, double output) {
+ this->input = input;
+ this->output = output;
+ }
+
+ bool operator==(const LinearEasingPoint& other) const {
+ return input == other.input && output == other.output;
+ }
+ bool operator!=(const LinearEasingPoint& other) const {
+ return !(*this == other);
+ }
+};
+
class GFX_KEYFRAME_ANIMATION_EXPORT LinearTimingFunction
: public TimingFunction {
public:
static std::unique_ptr<LinearTimingFunction> Create();
+ static std::unique_ptr<LinearTimingFunction> Create(
+ std::vector<LinearEasingPoint> points);
+
+ LinearTimingFunction& operator=(const LinearTimingFunction&) = delete;
~LinearTimingFunction() override;
// TimingFunction implementation.
@@ -134,8 +157,15 @@
std::unique_ptr<TimingFunction> Clone() const override;
double Velocity(double time) const override;
+ const LinearEasingPoint& Point(size_t i) const { return points_[i]; }
+ const std::vector<LinearEasingPoint>& Points() const { return points_; }
+ bool IsTrivial() const { return !points_.size(); }
+
private:
LinearTimingFunction();
+ explicit LinearTimingFunction(std::vector<LinearEasingPoint> points);
+ LinearTimingFunction(const LinearTimingFunction&);
+ std::vector<LinearEasingPoint> points_;
};
} // namespace gfx
diff --git a/ui/gfx/animation/keyframe/transition.cc b/ui/gfx/animation/keyframe/transition.cc
index f2305f0..69f44db 100644
--- a/ui/gfx/animation/keyframe/transition.cc
+++ b/ui/gfx/animation/keyframe/transition.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/keyframe/transition.h b/ui/gfx/animation/keyframe/transition.h
index d902f91..66999e2 100644
--- a/ui/gfx/animation/keyframe/transition.h
+++ b/ui/gfx/animation/keyframe/transition.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/linear_animation.cc b/ui/gfx/animation/linear_animation.cc
index 39f3671..db18a19 100644
--- a/ui/gfx/animation/linear_animation.cc
+++ b/ui/gfx/animation/linear_animation.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,7 +10,6 @@
#include <algorithm>
#include "base/command_line.h"
-#include "base/cxx17_backports.h"
#include "base/strings/string_number_conversions.h"
#include "ui/gfx/animation/animation_container.h"
#include "ui/gfx/animation/animation_delegate.h"
@@ -44,7 +43,7 @@
}
void LinearAnimation::SetCurrentValue(double new_value) {
- new_value = base::clamp(new_value, 0.0, 1.0);
+ new_value = std::clamp(new_value, 0.0, 1.0);
const base::TimeDelta time_delta = duration_ * (new_value - state_);
SetStartTime(start_time() - time_delta);
state_ = new_value;
diff --git a/ui/gfx/animation/linear_animation.h b/ui/gfx/animation/linear_animation.h
index d313ecd..f6348c4 100644
--- a/ui/gfx/animation/linear_animation.h
+++ b/ui/gfx/animation/linear_animation.h
@@ -1,11 +1,10 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_ANIMATION_LINEAR_ANIMATION_H_
#define UI_GFX_ANIMATION_LINEAR_ANIMATION_H_
-#include "base/macros.h"
#include "base/time/time.h"
#include "ui/gfx/animation/animation.h"
diff --git a/ui/gfx/animation/multi_animation.cc b/ui/gfx/animation/multi_animation.cc
index 09b4423..a663244 100644
--- a/ui/gfx/animation/multi_animation.cc
+++ b/ui/gfx/animation/multi_animation.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/multi_animation.h b/ui/gfx/animation/multi_animation.h
index 870e92f..5d4e2c5 100644
--- a/ui/gfx/animation/multi_animation.h
+++ b/ui/gfx/animation/multi_animation.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,7 +9,6 @@
#include <vector>
-#include "base/macros.h"
#include "base/time/time.h"
#include "ui/gfx/animation/animation.h"
#include "ui/gfx/animation/tween.h"
diff --git a/ui/gfx/animation/multi_animation_unittest.cc b/ui/gfx/animation/multi_animation_unittest.cc
index dec64d9..bbb23a0 100644
--- a/ui/gfx/animation/multi_animation_unittest.cc
+++ b/ui/gfx/animation/multi_animation_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/slide_animation.cc b/ui/gfx/animation/slide_animation.cc
index d525fbb..5bf2370 100644
--- a/ui/gfx/animation/slide_animation.cc
+++ b/ui/gfx/animation/slide_animation.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,7 +6,8 @@
#include <math.h>
-#include "base/cxx17_backports.h"
+#include <algorithm>
+
#include "ui/gfx/animation/animation_delegate.h"
namespace gfx {
@@ -72,7 +73,7 @@
}
void SlideAnimation::AnimateToState(double state) {
- state = Tween::CalculateValue(tween_type_, base::clamp(state, 0.0, 1.0));
+ state = Tween::CalculateValue(tween_type_, std::clamp(state, 0.0, 1.0));
if (state == 1.0)
direction_ = absl::nullopt;
diff --git a/ui/gfx/animation/slide_animation.h b/ui/gfx/animation/slide_animation.h
index 35e86f6..c20f5e8 100644
--- a/ui/gfx/animation/slide_animation.h
+++ b/ui/gfx/animation/slide_animation.h
@@ -1,11 +1,11 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_ANIMATION_SLIDE_ANIMATION_H_
#define UI_GFX_ANIMATION_SLIDE_ANIMATION_H_
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/animation/linear_animation.h"
#include "ui/gfx/animation/tween.h"
@@ -108,7 +108,7 @@
// Overridden from Animation.
void AnimateToState(double state) override;
- AnimationDelegate* target_;
+ raw_ptr<AnimationDelegate, DanglingUntriaged> target_;
Tween::Type tween_type_ = Tween::EASE_OUT;
diff --git a/ui/gfx/animation/slide_animation_unittest.cc b/ui/gfx/animation/slide_animation_unittest.cc
index 9a53c86..0945ba1 100644
--- a/ui/gfx/animation/slide_animation_unittest.cc
+++ b/ui/gfx/animation/slide_animation_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,7 +6,6 @@
#include <memory>
-#include "base/macros.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -25,62 +24,63 @@
animation_api_->Step(now + duration);
}
- std::unique_ptr<AnimationTestApi> animation_api_;
- std::unique_ptr<SlideAnimation> slide_animation_;
+ SlideAnimation* slide_animation() { return slide_animation_.get(); }
protected:
SlideAnimationTest()
: task_environment_(
- base::test::SingleThreadTaskEnvironment::MainThreadType::UI) {
- slide_animation_ = std::make_unique<SlideAnimation>(nullptr);
- animation_api_ = std::make_unique<AnimationTestApi>(slide_animation_.get());
- }
+ base::test::SingleThreadTaskEnvironment::MainThreadType::UI),
+ slide_animation_(std::make_unique<SlideAnimation>(nullptr)),
+ animation_api_(
+ std::make_unique<AnimationTestApi>(slide_animation_.get())) {}
private:
base::test::SingleThreadTaskEnvironment task_environment_;
+ const std::unique_ptr<SlideAnimation> slide_animation_;
+ const std::unique_ptr<AnimationTestApi> animation_api_;
};
// Tests animation construction.
TEST_F(SlideAnimationTest, InitialState) {
// By default, slide animations are 60 Hz, so the timer interval should be
// 1/60th of a second.
- EXPECT_EQ(1000 / 60, slide_animation_->timer_interval().InMilliseconds());
+ EXPECT_EQ(1000 / 60, slide_animation()->timer_interval().InMilliseconds());
// Duration defaults to 120 ms.
- EXPECT_EQ(120, slide_animation_->GetSlideDuration().InMilliseconds());
+ EXPECT_EQ(120, slide_animation()->GetSlideDuration().InMilliseconds());
// Slide is neither showing nor closing.
- EXPECT_FALSE(slide_animation_->IsShowing());
- EXPECT_FALSE(slide_animation_->IsClosing());
+ EXPECT_FALSE(slide_animation()->IsShowing());
+ EXPECT_FALSE(slide_animation()->IsClosing());
// Starts at 0.
- EXPECT_EQ(0.0, slide_animation_->GetCurrentValue());
+ EXPECT_EQ(0.0, slide_animation()->GetCurrentValue());
}
TEST_F(SlideAnimationTest, Basics) {
// Use linear tweening to make the math easier below.
- slide_animation_->SetTweenType(Tween::LINEAR);
+ slide_animation()->SetTweenType(Tween::LINEAR);
// Duration can be set after construction.
- slide_animation_->SetSlideDuration(base::Milliseconds(100));
- EXPECT_EQ(100, slide_animation_->GetSlideDuration().InMilliseconds());
+ slide_animation()->SetSlideDuration(base::Milliseconds(100));
+ EXPECT_EQ(100, slide_animation()->GetSlideDuration().InMilliseconds());
// Show toggles the appropriate state.
- slide_animation_->Show();
- EXPECT_TRUE(slide_animation_->IsShowing());
- EXPECT_FALSE(slide_animation_->IsClosing());
+ slide_animation()->Show();
+ EXPECT_TRUE(slide_animation()->IsShowing());
+ EXPECT_FALSE(slide_animation()->IsClosing());
// Simulate running the animation.
RunAnimationFor(base::Milliseconds(50));
- EXPECT_EQ(0.5, slide_animation_->GetCurrentValue());
+ EXPECT_EQ(0.5, slide_animation()->GetCurrentValue());
// We can start hiding mid-way through the animation.
- slide_animation_->Hide();
- EXPECT_FALSE(slide_animation_->IsShowing());
- EXPECT_TRUE(slide_animation_->IsClosing());
+ slide_animation()->Hide();
+ EXPECT_FALSE(slide_animation()->IsShowing());
+ EXPECT_TRUE(slide_animation()->IsClosing());
// Reset stops the animation.
- slide_animation_->Reset();
- EXPECT_EQ(0.0, slide_animation_->GetCurrentValue());
- EXPECT_FALSE(slide_animation_->IsShowing());
- EXPECT_FALSE(slide_animation_->IsClosing());
+ slide_animation()->Reset();
+ EXPECT_EQ(0.0, slide_animation()->GetCurrentValue());
+ EXPECT_FALSE(slide_animation()->IsShowing());
+ EXPECT_FALSE(slide_animation()->IsClosing());
}
// Tests that delegate is not notified when animation is running and is deleted.
@@ -104,139 +104,139 @@
// of 1 progress linearly.
TEST_F(SlideAnimationTest,
AnimationWithPartialProgressAndDefaultDampeningFactor) {
- slide_animation_->SetTweenType(Tween::LINEAR);
- slide_animation_->SetSlideDuration(base::Milliseconds(100));
- slide_animation_->Show();
- EXPECT_EQ(slide_animation_->GetCurrentValue(), 0.0);
+ slide_animation()->SetTweenType(Tween::LINEAR);
+ slide_animation()->SetSlideDuration(base::Milliseconds(100));
+ slide_animation()->Show();
+ EXPECT_EQ(slide_animation()->GetCurrentValue(), 0.0);
// Advance the animation to halfway done.
RunAnimationFor(base::Milliseconds(50));
- EXPECT_EQ(0.5, slide_animation_->GetCurrentValue());
+ EXPECT_EQ(0.5, slide_animation()->GetCurrentValue());
// Reverse the animation and run it for half of the remaining duration.
- slide_animation_->Hide();
+ slide_animation()->Hide();
RunAnimationFor(base::Milliseconds(25));
- EXPECT_EQ(0.25, slide_animation_->GetCurrentValue());
+ EXPECT_EQ(0.25, slide_animation()->GetCurrentValue());
// Reverse the animation again and run it for half of the remaining duration.
- slide_animation_->Show();
+ slide_animation()->Show();
RunAnimationFor(base::Milliseconds(37.5));
- EXPECT_EQ(0.625, slide_animation_->GetCurrentValue());
+ EXPECT_EQ(0.625, slide_animation()->GetCurrentValue());
}
// Tests that animations which are started partway and have a dampening factor
// of >1 progress sub-leanearly.
TEST_F(SlideAnimationTest,
AnimationWithPartialProgressAndNonDefaultDampeningFactor) {
- slide_animation_->SetTweenType(Tween::LINEAR);
- slide_animation_->SetDampeningValue(2.0);
- slide_animation_->SetSlideDuration(base::Milliseconds(100));
- slide_animation_->Show();
+ slide_animation()->SetTweenType(Tween::LINEAR);
+ slide_animation()->SetDampeningValue(2.0);
+ slide_animation()->SetSlideDuration(base::Milliseconds(100));
+ slide_animation()->Show();
// Advance the animation to halfway done.
RunAnimationFor(base::Milliseconds(50));
- EXPECT_EQ(0.5, slide_animation_->GetCurrentValue());
+ EXPECT_EQ(0.5, slide_animation()->GetCurrentValue());
// Reverse the animation and run it for the same duration, it should be
// sub-linear with dampening.
- slide_animation_->Hide();
+ slide_animation()->Hide();
RunAnimationFor(base::Milliseconds(50));
- EXPECT_GT(slide_animation_->GetCurrentValue(), 0);
+ EXPECT_GT(slide_animation()->GetCurrentValue(), 0);
}
// Tests that a mostly complete dampened animation takes a sub-linear
// amount of time to complete.
TEST_F(SlideAnimationTest, DampenedAnimationMostlyComplete) {
- slide_animation_->SetTweenType(Tween::LINEAR);
- slide_animation_->SetDampeningValue(2.0);
- slide_animation_->SetSlideDuration(base::Milliseconds(100));
- slide_animation_->Show();
+ slide_animation()->SetTweenType(Tween::LINEAR);
+ slide_animation()->SetDampeningValue(2.0);
+ slide_animation()->SetSlideDuration(base::Milliseconds(100));
+ slide_animation()->Show();
// Advance the animation to 1/10th of the way done.
RunAnimationFor(base::Milliseconds(10));
- EXPECT_EQ(0.1, slide_animation_->GetCurrentValue());
+ EXPECT_EQ(0.1, slide_animation()->GetCurrentValue());
// Reverse the animation and run it for 1/10th of the duration, it should not
// be complete.
- slide_animation_->Hide();
+ slide_animation()->Hide();
RunAnimationFor(base::Milliseconds(10));
- EXPECT_GT(slide_animation_->GetCurrentValue(), 0);
+ EXPECT_GT(slide_animation()->GetCurrentValue(), 0);
// Finish the animation and set up the test for a mostly complete show
// animation.
RunAnimationFor(base::Milliseconds(100));
- EXPECT_EQ(0, slide_animation_->GetCurrentValue());
- slide_animation_->Show();
+ EXPECT_EQ(0, slide_animation()->GetCurrentValue());
+ slide_animation()->Show();
// Advance the animation to 9/10th of the way done.
RunAnimationFor(base::Milliseconds(90));
- EXPECT_EQ(0.9, slide_animation_->GetCurrentValue());
+ EXPECT_EQ(0.9, slide_animation()->GetCurrentValue());
// Hide and then Show the animation to force the duration to be recalculated,
// then show for 1/10th of the duration and test that the animation is not
// complete.
- slide_animation_->Hide();
- slide_animation_->Show();
+ slide_animation()->Hide();
+ slide_animation()->Show();
RunAnimationFor(base::Milliseconds(10));
- EXPECT_LT(slide_animation_->GetCurrentValue(), 1);
+ EXPECT_LT(slide_animation()->GetCurrentValue(), 1);
RunAnimationFor(base::Milliseconds(40));
- EXPECT_EQ(1, slide_animation_->GetCurrentValue());
+ EXPECT_EQ(1, slide_animation()->GetCurrentValue());
}
// Tests that a mostly incomplete dampened animation takes a sub-linear amount
// of time to complete.
TEST_F(SlideAnimationTest, DampenedAnimationMostlyIncomplete) {
- slide_animation_->SetTweenType(Tween::LINEAR);
- slide_animation_->SetDampeningValue(2.0);
- slide_animation_->SetSlideDuration(base::Milliseconds(100));
- slide_animation_->Show();
+ slide_animation()->SetTweenType(Tween::LINEAR);
+ slide_animation()->SetDampeningValue(2.0);
+ slide_animation()->SetSlideDuration(base::Milliseconds(100));
+ slide_animation()->Show();
// Advance the animation to 1/10th of the way done.
RunAnimationFor(base::Milliseconds(10));
- EXPECT_EQ(0.1, slide_animation_->GetCurrentValue());
+ EXPECT_EQ(0.1, slide_animation()->GetCurrentValue());
// Hide and then Show the animation to force the duration to be recalculated,
// then show for 9/10th of the duration and test that the animation is not
// complete.
- slide_animation_->Hide();
- slide_animation_->Show();
+ slide_animation()->Hide();
+ slide_animation()->Show();
RunAnimationFor(base::Milliseconds(90));
- EXPECT_LT(slide_animation_->GetCurrentValue(), 1);
+ EXPECT_LT(slide_animation()->GetCurrentValue(), 1);
// Finish the animation and set up the test for a mostly incomplete hide
// animation.
RunAnimationFor(base::Milliseconds(100));
- EXPECT_EQ(1, slide_animation_->GetCurrentValue());
- slide_animation_->Hide();
+ EXPECT_EQ(1, slide_animation()->GetCurrentValue());
+ slide_animation()->Hide();
RunAnimationFor(base::Milliseconds(10));
- EXPECT_EQ(0.9, slide_animation_->GetCurrentValue());
+ EXPECT_EQ(0.9, slide_animation()->GetCurrentValue());
// Show and then hide the animation to recompute the duration, then run the
// animation for 9/10ths of the duration and test that the animation is not
// complete.
- slide_animation_->Show();
- slide_animation_->Hide();
+ slide_animation()->Show();
+ slide_animation()->Hide();
RunAnimationFor(base::Milliseconds(90));
- EXPECT_GT(slide_animation_->GetCurrentValue(), 0);
+ EXPECT_GT(slide_animation()->GetCurrentValue(), 0);
RunAnimationFor(base::Milliseconds(100));
- EXPECT_EQ(0, slide_animation_->GetCurrentValue());
+ EXPECT_EQ(0, slide_animation()->GetCurrentValue());
}
TEST_F(SlideAnimationTest, HideFromHalfway) {
auto container = base::MakeRefCounted<AnimationContainer>();
AnimationContainerTestApi test_api(container.get());
- slide_animation_->SetContainer(container.get());
- slide_animation_->SetTweenType(Tween::LINEAR);
- slide_animation_->SetSlideDuration(base::Milliseconds(100));
+ slide_animation()->SetContainer(container.get());
+ slide_animation()->SetTweenType(Tween::LINEAR);
+ slide_animation()->SetSlideDuration(base::Milliseconds(100));
- slide_animation_->Reset(0.5);
- EXPECT_FALSE(slide_animation_->is_animating());
- EXPECT_EQ(0.5, slide_animation_->GetCurrentValue());
+ slide_animation()->Reset(0.5);
+ EXPECT_FALSE(slide_animation()->is_animating());
+ EXPECT_EQ(0.5, slide_animation()->GetCurrentValue());
- slide_animation_->Hide();
- ASSERT_TRUE(slide_animation_->is_animating());
+ slide_animation()->Hide();
+ ASSERT_TRUE(slide_animation()->is_animating());
test_api.IncrementTime(base::Milliseconds(100));
- EXPECT_EQ(0.0, slide_animation_->GetCurrentValue());
+ EXPECT_EQ(0.0, slide_animation()->GetCurrentValue());
}
} // namespace gfx
diff --git a/ui/gfx/animation/test_animation_delegate.h b/ui/gfx/animation/test_animation_delegate.h
index 99da556..04b54c2 100644
--- a/ui/gfx/animation/test_animation_delegate.h
+++ b/ui/gfx/animation/test_animation_delegate.h
@@ -1,11 +1,10 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_ANIMATION_TEST_ANIMATION_DELEGATE_H_
#define UI_GFX_ANIMATION_TEST_ANIMATION_DELEGATE_H_
-#include "base/macros.h"
#include "base/run_loop.h"
#include "ui/gfx/animation/animation_delegate.h"
diff --git a/ui/gfx/animation/throb_animation.cc b/ui/gfx/animation/throb_animation.cc
index 2c2f90c..ac0f0ce 100644
--- a/ui/gfx/animation/throb_animation.cc
+++ b/ui/gfx/animation/throb_animation.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/animation/throb_animation.h b/ui/gfx/animation/throb_animation.h
index 6e9d094..8bbd3a6 100644
--- a/ui/gfx/animation/throb_animation.h
+++ b/ui/gfx/animation/throb_animation.h
@@ -1,11 +1,10 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_ANIMATION_THROB_ANIMATION_H_
#define UI_GFX_ANIMATION_THROB_ANIMATION_H_
-#include "base/macros.h"
#include "ui/gfx/animation/slide_animation.h"
namespace gfx {
diff --git a/ui/gfx/animation/tween.cc b/ui/gfx/animation/tween.cc
index 928f5dd..c02ffbf 100644
--- a/ui/gfx/animation/tween.cc
+++ b/ui/gfx/animation/tween.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -15,8 +15,13 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "ui/gfx/geometry/cubic_bezier.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/geometry/transform.h"
+#include "ui/gfx/geometry/transform_operations.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <float.h>
#endif
@@ -87,17 +92,38 @@
case ACCEL_LIN_DECEL_100:
return gfx::CubicBezier(0, 0, 0, 1).Solve(state);
+ case ACCEL_LIN_DECEL_100_3:
+ return gfx::CubicBezier(0, 0, 0, 0.97).Solve(state);
+
case ACCEL_20_DECEL_60:
return gfx::CubicBezier(0.2, 0, 0.4, 1).Solve(state);
+ case ACCEL_20_DECEL_100:
+ return gfx::CubicBezier(0.2, 0, 0, 1).Solve(state);
+
+ case ACCEL_30_DECEL_20_85:
+ return gfx::CubicBezier(0.3, 0, 0.8, 0.15).Solve(state);
+
+ case ACCEL_40_DECEL_20:
+ return gfx::CubicBezier(0.4, 0, 0.8, 1).Solve(state);
+
case ACCEL_80_DECEL_20:
return gfx::CubicBezier(0.8, 0, 0.8, 1).Solve(state);
case ACCEL_0_40_DECEL_100:
return gfx::CubicBezier(0, 0.4, 0, 1).Solve(state);
+ case ACCEL_40_DECEL_100_3:
+ return gfx::CubicBezier(0.40, 0, 0, 0.97).Solve(state);
+
case ACCEL_0_80_DECEL_80:
return gfx::CubicBezier(0, 0.8, 0.2, 1).Solve(state);
+
+ case ACCEL_0_100_DECEL_80:
+ return gfx::CubicBezier(0, 1, 0.2, 1).Solve(state);
+
+ case ACCEL_5_70_DECEL_90:
+ return gfx::CubicBezier(0.05, 0.7, 0.1, 1).Solve(state);
}
NOTREACHED();
@@ -123,9 +149,41 @@
return FloatToColorByte(blended_premultiplied / blended_alpha);
}
+float BlendColorComponentsFloat(float start,
+ float target,
+ float start_alpha,
+ float target_alpha,
+ float blended_alpha,
+ double progress) {
+ // Since progress can be outside [0, 1], blending can produce a value outside
+ // [0, 1].
+ float blended_premultiplied = Tween::FloatValueBetween(
+ progress, start * start_alpha, target * target_alpha);
+ return blended_premultiplied / blended_alpha;
+}
+
} // namespace
// static
+SkColor4f Tween::ColorValueBetween(double value,
+ SkColor4f start,
+ SkColor4f target) {
+ float start_a = start.fA;
+ float target_a = target.fA;
+ float blended_a = FloatValueBetween(value, start_a, target_a);
+ if (blended_a <= 0.f)
+ return SkColors::kTransparent;
+ blended_a = std::min(blended_a, 1.f);
+
+ auto blended_r = BlendColorComponentsFloat(start.fR, target.fR, start_a,
+ target_a, blended_a, value);
+ auto blended_g = BlendColorComponentsFloat(start.fG, target.fG, start_a,
+ target_a, blended_a, value);
+ auto blended_b = BlendColorComponentsFloat(start.fB, target.fB, start_a,
+ target_a, blended_a, value);
+
+ return SkColor4f{blended_r, blended_g, blended_b, blended_a};
+}
SkColor Tween::ColorValueBetween(double value, SkColor start, SkColor target) {
float start_a = SkColorGetA(start) / 255.f;
float target_a = SkColorGetA(target) / 255.f;
@@ -144,8 +202,8 @@
BlendColorComponents(SkColorGetB(start), SkColorGetB(target), start_a,
target_a, blended_a, value);
- return SkColorSetARGB(
- FloatToColorByte(blended_a), blended_r, blended_g, blended_b);
+ return SkColorSetARGB(FloatToColorByte(blended_a), blended_r, blended_g,
+ blended_b);
}
// static
@@ -182,7 +240,7 @@
delta--;
else
delta++;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return start + static_cast<int>(value * _nextafter(delta, 0));
#else
return start + static_cast<int>(value * nextafter(delta, 0));
diff --git a/ui/gfx/animation/tween.h b/ui/gfx/animation/tween.h
index da3d12d..efe7aa7 100644
--- a/ui/gfx/animation/tween.h
+++ b/ui/gfx/animation/tween.h
@@ -1,18 +1,12 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_ANIMATION_TWEEN_H_
#define UI_GFX_ANIMATION_TWEEN_H_
-#include "base/macros.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/animation/animation_export.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/rect_f.h"
-#include "ui/gfx/geometry/size_f.h"
-#include "ui/gfx/geometry/transform.h"
-#include "ui/gfx/geometry/transform_operations.h"
namespace base {
class TimeTicks;
@@ -20,6 +14,13 @@
namespace gfx {
+class Rect;
+class RectF;
+class Size;
+class SizeF;
+class Transform;
+class TransformOperations;
+
class ANIMATION_EXPORT Tween {
public:
enum Type {
@@ -62,21 +63,41 @@
// ACCEL_20_DECEL_20 = (0.2, 0, 0.8, 1): https://cubic-bezier.com/#.2,0,.8,1
// ACCEL_100_DECEL_100 = (1, 0, 0, 1): https://cubic-bezier.com/#1,0,0,1
// ACCEL_LIN_DECEL_LIN = (0, 0, 1, 1): https://cubic-bezier.com/#0,0,1,1
- // ACCEL_40_DECEL_80 = (0.4, 0, 0.2, 1): https://cubic-bezier.com/#.4,0,.2,1
+ // ACCEL_40_DECEL_20 = (0.4, 0, 0.8, 1): https://cubic-bezier.com/#.4,0,.8,1
+ // ACCEL_<1>_<2>_DECEL_<3>_<4> correspond to cubic bezier with curve
+ // parameters (0.01 * <1>, 0.01 * <2>, 1 - 0.01 * <3>, 1 - 0.01 * <4>). For
+ // example,
+ // ACCEL_0_20_DECEL_100_10 = (0, 0.2, 0, 0.9):
+ // https://cubic-bezier.com/#0,.2,0,.9
+ // ACCEL_40_DECEL_100_3 = (0.4, 0, 0,0.97):
+ // https://cubic-bezier.com/#.4,0,0,.97
+ // ACCEL_LIN_DECEL_100_3 = (0, 0, 0, 0.97):
+ // https://cubic-bezier.com/#0,0,0,.97
ACCEL_LIN_DECEL_60, // Pulling a small to medium element into a place.
ACCEL_LIN_DECEL_100, // Pulling a small to medium element into a place that
// has very fast deceleration.
+ // Starts with linear speed and soft deceleration. Use for elements that are
+ // not visible at the beginning of a transition, but are visible at the end.
+ ACCEL_LIN_DECEL_100_3,
ACCEL_20_DECEL_60, // Moving a small, low emphasis or responsive elements.
- ACCEL_80_DECEL_20, // Slow in and fast out with ease.
-
- // ACCEL_0_<1>_DECEL_<2> where <1> and <2> are used to express the
- // acceleration and deceleration speeds. The corresponding cubic bezier
- // curve parameters would be ( 0, 0.01 * <1>, 1 - 0.01 * <2>, 1 ).
+ ACCEL_20_DECEL_100,
+ ACCEL_30_DECEL_20_85,
+ ACCEL_40_DECEL_20,
+ // Moderate acceleration and soft deceleration. Used for elements that are
+ // visible at the beginning and end of a transition.
+ ACCEL_40_DECEL_100_3,
+ ACCEL_80_DECEL_20, // Slow in and fast out with ease.
ACCEL_0_40_DECEL_100, // Specialized curve with an emphasized deceleration
// drift.
ACCEL_0_80_DECEL_80, // Variant of ACCEL_0_40_DECEL_100 which drops in
// value faster, but flattens out into the drift
// sooner.
+
+ ACCEL_0_100_DECEL_80, // Variant of ACCEL_0_80_DECEL_80 which drops in
+ // value even faster.
+
+ ACCEL_5_70_DECEL_90, // Start at peak velocity and very soft
+ // deceleration.
};
Tween(const Tween&) = delete;
@@ -86,6 +107,9 @@
static double CalculateValue(Type type, double state);
// Conveniences for getting a value between a start and end point.
+ static SkColor4f ColorValueBetween(double value,
+ SkColor4f start,
+ SkColor4f target);
static SkColor ColorValueBetween(double value, SkColor start, SkColor target);
static double DoubleValueBetween(double value, double start, double target);
static float FloatValueBetween(double value, float start, float target);
diff --git a/ui/gfx/animation/tween_unittest.cc b/ui/gfx/animation/tween_unittest.cc
index 19ff9eb..152ba11 100644
--- a/ui/gfx/animation/tween_unittest.cc
+++ b/ui/gfx/animation/tween_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,9 +9,15 @@
#include "base/time/time.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/test/gfx_util.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/geometry/transform.h"
+#include "ui/gfx/geometry/transform_operations.h"
+#include "ui/gfx/geometry/test/geometry_util.h"
+#include "ui/gfx/test/sk_color_eq.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <float.h>
#endif
@@ -19,7 +25,7 @@
namespace {
double next_double(double d) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return _nextafter(d, d + 1);
#else
// Step two units of least precision towards positive infinity. On some 32
@@ -161,12 +167,8 @@
constexpr gfx::Rect r1(0, 0, 10, 10);
constexpr gfx::Rect r2(10, 10, 30, 30);
- // TODO(pkasting): Move the geometry test helpers from
- // cc/test/geometry_test_utils.h to ui/gfx/test/gfx_util.h or similar and use
- // a rect-comparison function here.
const gfx::Rect tweened = Tween::RectValueBetween(0.08, r1, r2);
- EXPECT_EQ(11, tweened.width());
- EXPECT_EQ(11, tweened.height());
+ EXPECT_EQ(gfx::Size(11, 11), tweened.size());
}
TEST(TweenTest, SizeValueBetween) {
diff --git a/ui/gfx/bidi_line_iterator.cc b/ui/gfx/bidi_line_iterator.cc
index cda076a..231392a 100644
--- a/ui/gfx/bidi_line_iterator.cc
+++ b/ui/gfx/bidi_line_iterator.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -28,24 +28,18 @@
} // namespace
-BiDiLineIterator::BiDiLineIterator() : bidi_(nullptr) {}
-
-BiDiLineIterator::~BiDiLineIterator() {
- if (bidi_) {
- ubidi_close(bidi_);
- bidi_ = nullptr;
- }
-}
+BiDiLineIterator::BiDiLineIterator() = default;
+BiDiLineIterator::~BiDiLineIterator() = default;
bool BiDiLineIterator::Open(const std::u16string& text,
base::i18n::TextDirection direction) {
DCHECK(!bidi_);
UErrorCode error = U_ZERO_ERROR;
- bidi_ = ubidi_openSized(static_cast<int>(text.length()), 0, &error);
+ bidi_.reset(ubidi_openSized(static_cast<int>(text.length()), 0, &error));
if (U_FAILURE(error))
return false;
- ubidi_setPara(bidi_, text.data(), static_cast<int>(text.length()),
+ ubidi_setPara(bidi_.get(), text.data(), static_cast<int>(text.length()),
GetParagraphLevelForDirection(direction), nullptr, &error);
return (U_SUCCESS(error));
}
@@ -53,7 +47,7 @@
int BiDiLineIterator::CountRuns() const {
DCHECK(bidi_ != nullptr);
UErrorCode error = U_ZERO_ERROR;
- const int runs = ubidi_countRuns(bidi_, &error);
+ const int runs = ubidi_countRuns(bidi_.get(), &error);
return U_SUCCESS(error) ? runs : 0;
}
@@ -61,14 +55,14 @@
int* start,
int* length) const {
DCHECK(bidi_ != nullptr);
- return ubidi_getVisualRun(bidi_, index, start, length);
+ return ubidi_getVisualRun(bidi_.get(), index, start, length);
}
void BiDiLineIterator::GetLogicalRun(int start,
int* end,
UBiDiLevel* level) const {
DCHECK(bidi_ != nullptr);
- ubidi_getLogicalRun(bidi_, start, end, level);
+ ubidi_getLogicalRun(bidi_.get(), start, end, level);
}
} // namespace gfx
diff --git a/ui/gfx/bidi_line_iterator.h b/ui/gfx/bidi_line_iterator.h
index cf18117..8d85d13 100644
--- a/ui/gfx/bidi_line_iterator.h
+++ b/ui/gfx/bidi_line_iterator.h
@@ -1,17 +1,18 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_BIDI_LINE_ITERATOR_H_
#define UI_GFX_BIDI_LINE_ITERATOR_H_
+#include <memory>
#include <string>
#include "base/i18n/rtl.h"
-#include "base/macros.h"
#include "third_party/icu/source/common/unicode/ubidi.h"
#include "third_party/icu/source/common/unicode/uchar.h"
#include "ui/gfx/gfx_export.h"
+#include "ui/gfx/ubidi_deleter.h"
namespace ui {
namespace gfx {
@@ -42,7 +43,7 @@
void GetLogicalRun(int start, int* end, UBiDiLevel* level) const;
private:
- UBiDi* bidi_;
+ std::unique_ptr<UBiDi, UBiDiDeleter> bidi_;
};
} // namespace gfx
diff --git a/ui/gfx/bidi_line_iterator_unittest.cc b/ui/gfx/bidi_line_iterator_unittest.cc
index 8a8f392..e2419aa 100644
--- a/ui/gfx/bidi_line_iterator_unittest.cc
+++ b/ui/gfx/bidi_line_iterator_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/blit.cc b/ui/gfx/blit.cc
index d7d74a5..cdead9a 100644
--- a/ui/gfx/blit.cc
+++ b/ui/gfx/blit.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/blit.h b/ui/gfx/blit.h
index b4a76ae..7e53c9f 100644
--- a/ui/gfx/blit.h
+++ b/ui/gfx/blit.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/blit_unittest.cc b/ui/gfx/blit_unittest.cc
index 1d70915..b78afe0 100644
--- a/ui/gfx/blit_unittest.cc
+++ b/ui/gfx/blit_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Copyright 2010 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -143,7 +143,7 @@
VerifyCanvasValues<5, 5>(canvas.get(), scroll_diagonal_expected);
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
TEST(Blit, WithSharedMemory) {
const int kCanvasWidth = 5;
diff --git a/ui/gfx/break_list.h b/ui/gfx/break_list.h
index 19c947f..afbc9fa 100644
--- a/ui/gfx/break_list.h
+++ b/ui/gfx/break_list.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -28,8 +28,8 @@
class BreakList {
public:
// The break type and const iterator, typedef'ed for convenience.
- typedef std::pair<size_t, T> Break;
- typedef typename std::vector<Break>::const_iterator const_iterator;
+ using Break = std::pair<size_t, T>;
+ using const_iterator = typename std::vector<Break>::const_iterator;
// Initialize a break at position 0 with the default or supplied |value|.
BreakList();
@@ -38,22 +38,27 @@
const std::vector<Break>& breaks() const { return breaks_; }
// Clear the breaks and set a break at position 0 with the supplied |value|.
- void SetValue(T value);
+ // Returns whether or not the breaks changed while applying the |value|.
+ bool SetValue(T value);
// Adjust the breaks to apply |value| over the supplied |range|.
- void ApplyValue(T value, const Range& range);
+ // Range |range| must be between [0, max_).
+ // Returns true if the breaks changed while applying the |value|.
+ bool ApplyValue(T value, const Range& range);
// Set the max position and trim any breaks at or beyond that position.
void SetMax(size_t max);
size_t max() const { return max_; }
- // Get the break applicable to |position| (at or preceeding |position|).
- typename std::vector<Break>::iterator GetBreak(size_t position);
- typename std::vector<Break>::const_iterator GetBreak(size_t position) const;
+ // Get the break applicable to |position| (at or preceding |position|).
+ // |position| must be between [0, max_).
+ // Returns a valid iterator. Can't return |break_.end()|.
+ const_iterator GetBreak(size_t position) const;
// Get the range of the supplied break; returns the break's start position and
// the next break's start position (or |max_| for the terminal break).
- Range GetRange(const typename BreakList<T>::const_iterator& i) const;
+ // Iterator |i| must be valid and must not be |break_.end()|.
+ Range GetRange(const const_iterator& i) const;
// Comparison functions for testing purposes.
bool EqualsValueForTesting(T value) const;
@@ -66,38 +71,46 @@
#endif
std::vector<Break> breaks_;
- size_t max_;
+ size_t max_ = 0;
};
-template<class T>
-BreakList<T>::BreakList() : breaks_(1, Break(0, T())), max_(0) {
-}
+template <class T>
+BreakList<T>::BreakList() : breaks_(1, Break(0, T())) {}
-template<class T>
-BreakList<T>::BreakList(T value) : breaks_(1, Break(0, value)), max_(0) {
-}
+template <class T>
+BreakList<T>::BreakList(T value) : breaks_(1, Break(0, value)) {}
-template<class T>
-void BreakList<T>::SetValue(T value) {
+template <class T>
+bool BreakList<T>::SetValue(T value) {
+ // Return false if setting |value| does not change the breaks.
+ if (breaks_.size() == 1 && breaks_[0].second == value)
+ return false;
+
breaks_.clear();
breaks_.push_back(Break(0, value));
+ return true;
}
-template<class T>
-void BreakList<T>::ApplyValue(T value, const Range& range) {
+template <class T>
+bool BreakList<T>::ApplyValue(T value, const Range& range) {
if (!range.IsValid() || range.is_empty())
- return;
+ return false;
DCHECK(!breaks_.empty());
DCHECK(!range.is_reversed());
DCHECK(Range(0, static_cast<uint32_t>(max_)).Contains(range));
+ // Return false if setting |value| does not change the breaks.
+ const_iterator start = GetBreak(range.start());
+ if (start->second == value && GetRange(start).Contains(range))
+ return false;
+
// Erase any breaks in |range|, then add start and end breaks as needed.
- typename std::vector<Break>::iterator start = GetBreak(range.start());
start += start->first < range.start() ? 1 : 0;
- typename std::vector<Break>::iterator end = GetBreak(range.end());
+ const_iterator end =
+ range.end() == max_ ? breaks_.cend() - 1 : GetBreak(range.end());
T trailing_value = end->second;
- typename std::vector<Break>::iterator i =
- start == breaks_.end() ? start : breaks_.erase(start, end + 1);
+ const_iterator i =
+ start == breaks_.cend() ? start : breaks_.erase(start, end + 1);
if (range.start() == 0 || (i - 1)->second != value)
i = breaks_.insert(i, Break(range.start(), value)) + 1;
if (trailing_value != value && range.end() != max_)
@@ -106,13 +119,18 @@
#ifndef NDEBUG
CheckBreaks();
#endif
+
+ return true;
}
template<class T>
void BreakList<T>::SetMax(size_t max) {
- typename std::vector<Break>::iterator i = GetBreak(max);
- i += (i == breaks_.begin() || i->first < max) ? 1 : 0;
- breaks_.erase(i, breaks_.end());
+ if (max < max_) {
+ const_iterator i = GetBreak(max);
+ if (i == breaks_.begin() || i->first < max)
+ i++;
+ breaks_.erase(i, breaks_.end());
+ }
max_ = max;
#ifndef NDEBUG
@@ -120,26 +138,26 @@
#endif
}
-template<class T>
-typename std::vector<std::pair<size_t, T> >::iterator BreakList<T>::GetBreak(
- size_t position) {
- typename std::vector<Break>::iterator i = breaks_.end() - 1;
- for (; i != breaks_.begin() && i->first > position; --i);
- return i;
-}
-
-template<class T>
-typename std::vector<std::pair<size_t, T> >::const_iterator
- BreakList<T>::GetBreak(size_t position) const {
- typename std::vector<Break>::const_iterator i = breaks_.end() - 1;
- for (; i != breaks_.begin() && i->first > position; --i);
- return i;
+template <class T>
+typename BreakList<T>::const_iterator BreakList<T>::GetBreak(
+ size_t position) const {
+ DCHECK(!breaks_.empty());
+ DCHECK_LT(position, max_);
+ // Find the iterator with a 'strictly greater' position and return the
+ // previous one.
+ return std::upper_bound(breaks_.cbegin(), breaks_.cend(), position,
+ [](size_t offset, const Break& value) {
+ return offset < value.first;
+ }) -
+ 1;
}
template<class T>
Range BreakList<T>::GetRange(
const typename BreakList<T>::const_iterator& i) const {
- const typename BreakList<T>::const_iterator next = i + 1;
+ // BreakLists are never empty. Iterator should always be valid.
+ DCHECK(i != breaks_.end());
+ const const_iterator next = i + 1;
return Range(i->first, next == breaks_.end() ? max_ : next->first);
}
@@ -161,6 +179,7 @@
#ifndef NDEBUG
template <class T>
void BreakList<T>::CheckBreaks() {
+ DCHECK(!breaks_.empty()) << "BreakList cannot be empty";
DCHECK_EQ(breaks_[0].first, 0U) << "The first break must be at position 0.";
for (size_t i = 0; i < breaks_.size() - 1; ++i) {
DCHECK_LT(breaks_[i].first, breaks_[i + 1].first) << "Break out of order.";
diff --git a/ui/gfx/break_list_unittest.cc b/ui/gfx/break_list_unittest.cc
index 81a6621..4df5f8b 100644
--- a/ui/gfx/break_list_unittest.cc
+++ b/ui/gfx/break_list_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,7 +6,6 @@
#include <stddef.h>
-#include "base/cxx17_backports.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/range/range.h"
@@ -29,6 +28,21 @@
EXPECT_TRUE(color_breaks.EqualsValueForTesting(SK_ColorBLACK));
}
+TEST_F(BreakListTest, SetValueChanged) {
+ BreakList<bool> breaks(false);
+ EXPECT_FALSE(breaks.SetValue(false));
+ EXPECT_TRUE(breaks.SetValue(true));
+ EXPECT_FALSE(breaks.SetValue(true));
+ EXPECT_TRUE(breaks.SetValue(false));
+
+ const size_t max = 99;
+ breaks.SetMax(max);
+ breaks.ApplyValue(true, Range(0, 2));
+ breaks.ApplyValue(true, Range(3, 6));
+ EXPECT_TRUE(breaks.SetValue(false));
+ EXPECT_FALSE(breaks.SetValue(false));
+}
+
TEST_F(BreakListTest, ApplyValue) {
BreakList<bool> breaks(false);
const size_t max = 99;
@@ -103,6 +117,27 @@
EXPECT_TRUE(breaks.EqualsForTesting(overlap));
}
+TEST_F(BreakListTest, ApplyValueChanged) {
+ BreakList<bool> breaks(false);
+ const size_t max = 99;
+ breaks.SetMax(max);
+
+ // Set two ranges.
+ EXPECT_TRUE(breaks.ApplyValue(true, Range(0, 5)));
+ EXPECT_TRUE(breaks.ApplyValue(true, Range(9, 10)));
+
+ // Setting sub-ranges should be a no-op.
+ EXPECT_FALSE(breaks.ApplyValue(true, Range(0, 2)));
+ EXPECT_FALSE(breaks.ApplyValue(true, Range(1, 3)));
+
+ // Merge the two ranges.
+ EXPECT_TRUE(breaks.ApplyValue(true, Range(2, 10)));
+
+ // Setting sub-ranges should be a no-op.
+ EXPECT_FALSE(breaks.ApplyValue(true, Range(0, 2)));
+ EXPECT_FALSE(breaks.ApplyValue(true, Range(1, 3)));
+}
+
TEST_F(BreakListTest, SetMax) {
// Ensure values adjust to accommodate max position changes.
BreakList<bool> breaks(false);
@@ -145,20 +180,12 @@
size_t break_index;
Range range;
} cases[] = {
- { 0, 0, Range(0, 1) },
- { 1, 1, Range(1, 2) },
- { 2, 2, Range(2, 4) },
- { 3, 2, Range(2, 4) },
- { 4, 3, Range(4, 6) },
- { 5, 3, Range(4, 6) },
- { 6, 4, Range(6, 8) },
- { 7, 4, Range(6, 8) },
- // Positions at or beyond the max simply return the last break and range.
- { 8, 4, Range(6, 8) },
- { 9, 4, Range(6, 8) },
+ {0, 0, Range(0, 1)}, {1, 1, Range(1, 2)}, {2, 2, Range(2, 4)},
+ {3, 2, Range(2, 4)}, {4, 3, Range(4, 6)}, {5, 3, Range(4, 6)},
+ {6, 4, Range(6, 8)}, {7, 4, Range(6, 8)},
};
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
BreakList<bool>::const_iterator it = breaks.GetBreak(cases[i].position);
EXPECT_EQ(breaks.breaks()[cases[i].break_index], *it);
EXPECT_EQ(breaks.GetRange(it), cases[i].range);
diff --git a/ui/gfx/buffer_format_util.cc b/ui/gfx/buffer_format_util.cc
index 0ca68b9..430ab56 100644
--- a/ui/gfx/buffer_format_util.cc
+++ b/ui/gfx/buffer_format_util.cc
@@ -1,11 +1,10 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/buffer_format_util.h"
#include "base/check_op.h"
-#include "base/cxx17_backports.h"
#include "base/notreached.h"
#include "base/numerics/safe_math.h"
#include "ui/gfx/switches.h"
@@ -13,23 +12,18 @@
namespace gfx {
namespace {
-const BufferFormat kBufferFormats[] = {BufferFormat::R_8,
- BufferFormat::R_16,
- BufferFormat::RG_88,
- BufferFormat::BGR_565,
- BufferFormat::RGBA_4444,
- BufferFormat::RGBX_8888,
- BufferFormat::RGBA_8888,
- BufferFormat::BGRX_8888,
- BufferFormat::BGRA_1010102,
- BufferFormat::RGBA_1010102,
- BufferFormat::BGRA_8888,
- BufferFormat::RGBA_F16,
- BufferFormat::YUV_420_BIPLANAR,
- BufferFormat::YVU_420,
- BufferFormat::P010};
+const BufferFormat kBufferFormats[] = {
+ BufferFormat::R_8, BufferFormat::R_16,
+ BufferFormat::RG_88, BufferFormat::RG_1616,
+ BufferFormat::BGR_565, BufferFormat::RGBA_4444,
+ BufferFormat::RGBX_8888, BufferFormat::RGBA_8888,
+ BufferFormat::BGRX_8888, BufferFormat::BGRA_1010102,
+ BufferFormat::RGBA_1010102, BufferFormat::BGRA_8888,
+ BufferFormat::RGBA_F16, BufferFormat::YUV_420_BIPLANAR,
+ BufferFormat::YVU_420, BufferFormat::YUVA_420_TRIPLANAR,
+ BufferFormat::P010};
-static_assert(base::size(kBufferFormats) ==
+static_assert(std::size(kBufferFormats) ==
(static_cast<int>(BufferFormat::LAST) + 1),
"BufferFormat::LAST must be last value of kBufferFormats");
@@ -37,7 +31,7 @@
std::vector<BufferFormat> GetBufferFormatsForTesting() {
return std::vector<BufferFormat>(kBufferFormats,
- kBufferFormats + base::size(kBufferFormats));
+ kBufferFormats + std::size(kBufferFormats));
}
size_t AlphaBitsForBufferFormat(BufferFormat format) {
@@ -50,12 +44,14 @@
case BufferFormat::RGBA_1010102:
return 2;
case BufferFormat::BGRA_8888:
+ case BufferFormat::YUVA_420_TRIPLANAR:
return 8;
case BufferFormat::RGBA_F16:
return 16;
case BufferFormat::R_8:
case BufferFormat::R_16:
case BufferFormat::RG_88:
+ case BufferFormat::RG_1616:
case BufferFormat::BGR_565:
case BufferFormat::RGBX_8888:
case BufferFormat::BGRX_8888:
@@ -73,6 +69,7 @@
case BufferFormat::R_8:
case BufferFormat::R_16:
case BufferFormat::RG_88:
+ case BufferFormat::RG_1616:
case BufferFormat::BGR_565:
case BufferFormat::RGBA_4444:
case BufferFormat::RGBX_8888:
@@ -87,6 +84,7 @@
case BufferFormat::P010:
return 2;
case BufferFormat::YVU_420:
+ case BufferFormat::YUVA_420_TRIPLANAR:
return 3;
}
NOTREACHED();
@@ -98,6 +96,7 @@
case BufferFormat::R_8:
case BufferFormat::R_16:
case BufferFormat::RG_88:
+ case BufferFormat::RG_1616:
case BufferFormat::BGR_565:
case BufferFormat::RGBA_4444:
case BufferFormat::RGBX_8888:
@@ -109,16 +108,98 @@
case BufferFormat::RGBA_F16:
return 1;
case BufferFormat::YVU_420: {
- static size_t factor[] = {1, 2, 2};
- DCHECK_LT(static_cast<size_t>(plane), base::size(factor));
+ constexpr size_t factor[] = {1, 2, 2};
+ DCHECK_LT(plane, std::size(factor));
return factor[plane];
}
case BufferFormat::YUV_420_BIPLANAR:
case BufferFormat::P010: {
- static size_t factor[] = {1, 2};
- DCHECK_LT(static_cast<size_t>(plane), base::size(factor));
+ constexpr size_t factor[] = {1, 2};
+ DCHECK_LT(plane, std::size(factor));
return factor[plane];
}
+ case BufferFormat::YUVA_420_TRIPLANAR: {
+ constexpr size_t factor[] = {1, 2, 1};
+ DCHECK_LT(plane, std::size(factor));
+ return factor[plane];
+ }
+ }
+ NOTREACHED();
+ return 0;
+}
+
+base::CheckedNumeric<size_t> PlaneWidthForBufferFormatChecked(
+ size_t width,
+ BufferFormat format,
+ size_t plane) {
+ const size_t subsample = SubsamplingFactorForBufferFormat(format, plane);
+ return base::CheckDiv(base::CheckAdd(width, base::CheckSub(subsample, 1)),
+ subsample);
+}
+
+base::CheckedNumeric<size_t> PlaneHeightForBufferFormatChecked(
+ size_t height,
+ BufferFormat format,
+ size_t plane) {
+ const size_t subsample = SubsamplingFactorForBufferFormat(format, plane);
+ return base::CheckDiv(base::CheckAdd(height, base::CheckSub(subsample, 1)),
+ subsample);
+}
+
+size_t BytesPerPixelForBufferFormat(BufferFormat format, size_t plane) {
+ switch (format) {
+ case BufferFormat::R_8:
+ return 1;
+ case BufferFormat::R_16:
+ case BufferFormat::RG_88:
+ case BufferFormat::BGR_565:
+ case BufferFormat::RGBA_4444:
+ return 2;
+ case BufferFormat::RG_1616:
+ case BufferFormat::BGRX_8888:
+ case BufferFormat::BGRA_1010102:
+ case BufferFormat::RGBA_1010102:
+ case BufferFormat::RGBX_8888:
+ case BufferFormat::RGBA_8888:
+ case BufferFormat::BGRA_8888:
+ return 4;
+ case BufferFormat::RGBA_F16:
+ return 8;
+ case BufferFormat::YVU_420:
+ return 1;
+ case BufferFormat::YUV_420_BIPLANAR:
+ case BufferFormat::YUVA_420_TRIPLANAR:
+ return SubsamplingFactorForBufferFormat(format, plane);
+ case BufferFormat::P010:
+ return 2 * SubsamplingFactorForBufferFormat(format, plane);
+ }
+ NOTREACHED();
+ return 0;
+}
+
+size_t RowByteAlignmentForBufferFormat(BufferFormat format, size_t plane) {
+ switch (format) {
+ case BufferFormat::R_8:
+ case BufferFormat::R_16:
+ case BufferFormat::RG_88:
+ case BufferFormat::BGR_565:
+ case BufferFormat::RGBA_4444:
+ case BufferFormat::RG_1616:
+ case BufferFormat::BGRX_8888:
+ case BufferFormat::BGRA_1010102:
+ case BufferFormat::RGBA_1010102:
+ case BufferFormat::RGBX_8888:
+ case BufferFormat::RGBA_8888:
+ case BufferFormat::BGRA_8888:
+ return 4;
+ case BufferFormat::RGBA_F16:
+ return 8;
+ case BufferFormat::YVU_420:
+ return 1;
+ case BufferFormat::YUV_420_BIPLANAR:
+ case BufferFormat::YUVA_420_TRIPLANAR:
+ case BufferFormat::P010:
+ return BytesPerPixelForBufferFormat(format, plane);
}
NOTREACHED();
return 0;
@@ -135,56 +216,45 @@
BufferFormat format,
size_t plane,
size_t* size_in_bytes) {
- base::CheckedNumeric<size_t> checked_size = width;
- switch (format) {
- case BufferFormat::R_8:
- checked_size += 3;
- if (!checked_size.IsValid())
- return false;
- *size_in_bytes = (checked_size & ~0x3).ValueOrDie();
- return true;
- case BufferFormat::R_16:
- case BufferFormat::RG_88:
- case BufferFormat::BGR_565:
- case BufferFormat::RGBA_4444:
- checked_size *= 2;
- checked_size += 3;
- if (!checked_size.IsValid())
- return false;
- *size_in_bytes = (checked_size & ~0x3).ValueOrDie();
- return true;
- case BufferFormat::BGRX_8888:
- case BufferFormat::BGRA_1010102:
- case BufferFormat::RGBA_1010102:
- case BufferFormat::RGBX_8888:
- case BufferFormat::RGBA_8888:
- case BufferFormat::BGRA_8888:
- checked_size *= 4;
- if (!checked_size.IsValid())
- return false;
- *size_in_bytes = checked_size.ValueOrDie();
- return true;
- case BufferFormat::RGBA_F16:
- checked_size *= 8;
- if (!checked_size.IsValid())
- return false;
- *size_in_bytes = checked_size.ValueOrDie();
- return true;
- case BufferFormat::YVU_420:
- DCHECK_EQ(width % 2, 0u);
- *size_in_bytes = width / SubsamplingFactorForBufferFormat(format, plane);
- return true;
- case BufferFormat::YUV_420_BIPLANAR:
- DCHECK_EQ(width % 2, 0u);
- *size_in_bytes = width;
- return true;
- case BufferFormat::P010:
- DCHECK_EQ(width % 2, 0u);
- *size_in_bytes = 2 * width;
- return true;
+ base::CheckedNumeric<size_t> checked_size =
+ PlaneWidthForBufferFormatChecked(width, format, plane);
+ checked_size *= BytesPerPixelForBufferFormat(format, plane);
+ const size_t alignment = RowByteAlignmentForBufferFormat(format, plane);
+ checked_size = (checked_size + alignment - 1) & ~(alignment - 1);
+ if (!checked_size.IsValid())
+ return false;
+
+ *size_in_bytes = checked_size.ValueOrDie();
+ return true;
+}
+
+size_t PlaneSizeForBufferFormat(const Size& size,
+ BufferFormat format,
+ size_t plane) {
+ size_t plane_size = 0;
+ bool valid =
+ PlaneSizeForBufferFormatChecked(size, format, plane, &plane_size);
+ DCHECK(valid);
+ return plane_size;
+}
+
+bool PlaneSizeForBufferFormatChecked(const Size& size,
+ BufferFormat format,
+ size_t plane,
+ size_t* size_in_bytes) {
+ size_t row_size = 0;
+ if (!RowSizeForBufferFormatChecked(base::checked_cast<size_t>(size.width()),
+ format, plane, &row_size)) {
+ return false;
}
- NOTREACHED();
- return false;
+ base::CheckedNumeric<size_t> checked_plane_size = row_size;
+ checked_plane_size *= PlaneHeightForBufferFormatChecked(
+ base::checked_cast<size_t>(size.height()), format, plane);
+ if (!checked_plane_size.IsValid())
+ return false;
+
+ *size_in_bytes = checked_plane_size.ValueOrDie();
+ return true;
}
size_t BufferSizeForBufferFormat(const Size& size, BufferFormat format) {
@@ -200,18 +270,14 @@
base::CheckedNumeric<size_t> checked_size = 0;
size_t num_planes = NumberOfPlanesForLinearBufferFormat(format);
for (size_t i = 0; i < num_planes; ++i) {
- size_t row_size = 0;
- if (!RowSizeForBufferFormatChecked(size.width(), format, i, &row_size))
+ size_t plane_size = 0;
+ if (!PlaneSizeForBufferFormatChecked(size, format, i, &plane_size))
return false;
- base::CheckedNumeric<size_t> checked_plane_size = row_size;
- checked_plane_size *= size.height() /
- SubsamplingFactorForBufferFormat(format, i);
- if (!checked_plane_size.IsValid())
- return false;
- checked_size += checked_plane_size.ValueOrDie();
+ checked_size += plane_size;
if (!checked_size.IsValid())
return false;
}
+
*size_in_bytes = checked_size.ValueOrDie();
return true;
}
@@ -220,10 +286,12 @@
BufferFormat format,
size_t plane) {
DCHECK_LT(plane, gfx::NumberOfPlanesForLinearBufferFormat(format));
+
switch (format) {
case BufferFormat::R_8:
case BufferFormat::R_16:
case BufferFormat::RG_88:
+ case BufferFormat::RG_1616:
case BufferFormat::BGR_565:
case BufferFormat::RGBA_4444:
case BufferFormat::RGBX_8888:
@@ -234,23 +302,15 @@
case BufferFormat::BGRA_8888:
case BufferFormat::RGBA_F16:
return 0;
- case BufferFormat::YVU_420: {
- static size_t offset_in_2x2_sub_sampling_sizes[] = {0, 4, 5};
- DCHECK_LT(plane, base::size(offset_in_2x2_sub_sampling_sizes));
- return offset_in_2x2_sub_sampling_sizes[plane] * (size.width() / 2) *
- (size.height() / 2);
- }
- case gfx::BufferFormat::YUV_420_BIPLANAR: {
- static size_t offset_in_2x2_sub_sampling_sizes[] = {0, 4};
- DCHECK_LT(plane, base::size(offset_in_2x2_sub_sampling_sizes));
- return offset_in_2x2_sub_sampling_sizes[plane] * (size.width() / 2) *
- (size.height() / 2);
- }
+ case BufferFormat::YVU_420:
+ case BufferFormat::YUV_420_BIPLANAR:
+ case BufferFormat::YUVA_420_TRIPLANAR:
case BufferFormat::P010: {
- static size_t offset_in_2x2_sub_sampling_sizes[] = {0, 4};
- DCHECK_LT(plane, base::size(offset_in_2x2_sub_sampling_sizes));
- return 2 * offset_in_2x2_sub_sampling_sizes[plane] *
- (size.width() / 2 + size.height() / 2);
+ size_t offset = 0;
+ for (size_t i = 0; i < plane; i++) {
+ offset += PlaneSizeForBufferFormat(size, format, i);
+ }
+ return offset;
}
}
NOTREACHED();
@@ -265,6 +325,8 @@
return "R_16";
case BufferFormat::RG_88:
return "RG_88";
+ case BufferFormat::RG_1616:
+ return "RG_1616";
case BufferFormat::BGR_565:
return "BGR_565";
case BufferFormat::RGBA_4444:
@@ -287,6 +349,8 @@
return "YVU_420";
case BufferFormat::YUV_420_BIPLANAR:
return "YUV_420_BIPLANAR";
+ case BufferFormat::YUVA_420_TRIPLANAR:
+ return "YUVA_420_TRIPLANAR";
case BufferFormat::P010:
return "P010";
}
@@ -308,6 +372,8 @@
return "U";
case BufferPlane::V:
return "V";
+ case BufferPlane::A:
+ return "A";
}
NOTREACHED() << "Invalid BufferPlane: "
<< static_cast<typename std::underlying_type<BufferPlane>::type>(
@@ -315,8 +381,12 @@
return "Invalid Plane";
}
-bool AllowOddHeightMultiPlanarBuffers() {
+bool IsOddHeightMultiPlanarBuffersAllowed() {
return base::FeatureList::IsEnabled(features::kOddHeightMultiPlanarBuffers);
}
+bool IsOddWidthMultiPlanarBuffersAllowed() {
+ return base::FeatureList::IsEnabled(features::kOddWidthMultiPlanarBuffers);
+}
+
} // namespace gfx
diff --git a/ui/gfx/buffer_format_util.h b/ui/gfx/buffer_format_util.h
index a73b264..35f4592 100644
--- a/ui/gfx/buffer_format_util.h
+++ b/ui/gfx/buffer_format_util.h
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -29,24 +29,40 @@
GFX_EXPORT size_t SubsamplingFactorForBufferFormat(BufferFormat format,
size_t plane);
+// Returns the alignment requirement to store a row of the given zero-indexed
+// |plane| of |format|.
+GFX_EXPORT size_t RowByteAlignmentForBufferFormat(BufferFormat format,
+ size_t plane);
+
// Returns the number of bytes used to store a row of the given zero-indexed
// |plane| of |format|.
GFX_EXPORT size_t RowSizeForBufferFormat(size_t width,
BufferFormat format,
size_t plane);
-GFX_EXPORT bool RowSizeForBufferFormatChecked(size_t width,
- BufferFormat format,
- size_t plane,
- size_t* size_in_bytes)
- WARN_UNUSED_RESULT;
+[[nodiscard]] GFX_EXPORT bool RowSizeForBufferFormatChecked(
+ size_t width,
+ BufferFormat format,
+ size_t plane,
+ size_t* size_in_bytes);
+
+// Returns the number of bytes used to the plane of a given |format|.
+GFX_EXPORT size_t PlaneSizeForBufferFormat(const Size& size,
+ BufferFormat format,
+ size_t plane);
+[[nodiscard]] GFX_EXPORT bool PlaneSizeForBufferFormatChecked(
+ const Size& size,
+ BufferFormat format,
+ size_t plane,
+ size_t* size_in_bytes);
// Returns the number of bytes used to store all the planes of a given |format|.
GFX_EXPORT size_t BufferSizeForBufferFormat(const Size& size,
BufferFormat format);
-GFX_EXPORT bool BufferSizeForBufferFormatChecked(const Size& size,
- BufferFormat format,
- size_t* size_in_bytes)
- WARN_UNUSED_RESULT;
+
+[[nodiscard]] GFX_EXPORT bool BufferSizeForBufferFormatChecked(
+ const Size& size,
+ BufferFormat format,
+ size_t* size_in_bytes);
GFX_EXPORT size_t BufferOffsetForBufferFormat(const Size& size,
BufferFormat format,
@@ -62,8 +78,9 @@
// tricky when the size of the primary plane is odd, because the subsampled
// planes will have a size that is not a divisor of the primary plane's size.
// This indicates that odd height multiplanar formats are supported.
-GFX_EXPORT bool AllowOddHeightMultiPlanarBuffers();
+GFX_EXPORT bool IsOddHeightMultiPlanarBuffersAllowed();
+GFX_EXPORT bool IsOddWidthMultiPlanarBuffersAllowed();
} // namespace gfx
#endif // UI_GFX_BUFFER_FORMAT_UTIL_H_
diff --git a/ui/gfx/buffer_types.h b/ui/gfx/buffer_types.h
index 1ae77fc..50fe152 100644
--- a/ui/gfx/buffer_types.h
+++ b/ui/gfx/buffer_types.h
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -13,10 +13,11 @@
// The format needs to be taken into account when mapping a buffer into the
// client's address space.
-enum class BufferFormat {
+enum class BufferFormat : uint8_t {
R_8,
R_16,
RG_88,
+ RG_1616,
BGR_565,
RGBA_4444,
RGBX_8888,
@@ -28,6 +29,7 @@
RGBA_F16,
YVU_420,
YUV_420_BIPLANAR,
+ YUVA_420_TRIPLANAR,
P010,
LAST = P010
@@ -35,11 +37,13 @@
// The usage mode affects how a buffer can be used. Only buffers created with
// *_CPU_READ_WRITE_* can be mapped into the client's address space and accessed
-// by the CPU. SCANOUT implies GPU_READ_WRITE.
-// *_VDA_WRITE is for cases where a video decode accellerator writes into
-// the buffers.
+// by the CPU.
+// *_VDA_WRITE is for cases where a video decode accelerator writes into the
+// buffers.
// PROTECTED_* are for HW protected buffers that cannot be read by the CPU and
// can only be read in protected GPU contexts or scanned out to overlays.
+// At present, SCANOUT implies GPU_READ_WRITE. This doesn't apply to other
+// SCANOUT_* values.
// TODO(reveman): Add GPU_READ_WRITE for use-cases where SCANOUT is not
// required.
@@ -78,20 +82,22 @@
// SharedImage.
enum class BufferPlane {
// For single-plane GpuMemoryBuffer, this refers to that single plane. For
- // YUV_420, YUV_420_BIPLANAR, and P010 GpuMemoryBuffers, this refers to an
- // RGB representation of the planes (either bound directly as a texture or
- // created through an extra copy).
+ // YUV_420, YUV_420_BIPLANAR, YUVA_420_TRIPLANAR, and P010 GpuMemoryBuffers,
+ // this refers to an RGB representation of the planes (either bound directly
+ // as a texture or created through an extra copy).
DEFAULT,
- // The Y plane for YUV_420, YUV_420_BIPLANAR, and P010.
+ // The Y plane for YUV_420, YUV_420_BIPLANAR, YUVA_420_TRIPLANAR, and P010.
Y,
- // The UV plane for YUV_420_BIPLANAR and P010.
+ // The UV plane for YUV_420_BIPLANAR, YUVA_420_TRIPLANAR and P010.
UV,
// The U plane for YUV_420.
U,
// The V plane for YUV_420.
V,
+ // The A plane for YUVA_420_TRIPLANAR.
+ A,
- LAST = V
+ LAST = A
};
} // namespace gfx
diff --git a/ui/gfx/buffer_usage_util.cc b/ui/gfx/buffer_usage_util.cc
index d2a66f6..69fcd5c 100644
--- a/ui/gfx/buffer_usage_util.cc
+++ b/ui/gfx/buffer_usage_util.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/buffer_usage_util.h b/ui/gfx/buffer_usage_util.h
index cf3c41b..c6267c2 100644
--- a/ui/gfx/buffer_usage_util.h
+++ b/ui/gfx/buffer_usage_util.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ca_layer_params.cc b/ui/gfx/ca_layer_params.cc
index 1824bc5..5fa6a4f 100644
--- a/ui/gfx/ca_layer_params.cc
+++ b/ui/gfx/ca_layer_params.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ca_layer_params.h b/ui/gfx/ca_layer_params.h
index 64af450..86d5be8 100644
--- a/ui/gfx/ca_layer_params.h
+++ b/ui/gfx/ca_layer_params.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,7 +9,7 @@
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gfx_export.h"
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_APPLE)
#include "ui/gfx/mac/io_surface.h"
#endif
@@ -25,6 +25,16 @@
CALayerParams& operator=(const CALayerParams& params);
~CALayerParams();
+ bool operator==(const CALayerParams& params) const {
+ return is_empty == params.is_empty &&
+ ca_context_id == params.ca_context_id &&
+#if BUILDFLAG(IS_APPLE)
+ io_surface_mach_port == params.io_surface_mach_port &&
+#endif
+ pixel_size == params.pixel_size &&
+ scale_factor == params.scale_factor;
+ }
+
// The |is_empty| flag is used to short-circuit code to handle CALayerParams
// on non-macOS platforms.
bool is_empty = true;
@@ -37,7 +47,7 @@
// Used to set the contents of a CALayer in the browser to an IOSurface that
// is specified by the GPU process. This is non-null iff |ca_context_id| is
// zero.
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_APPLE)
gfx::ScopedRefCountedIOSurfaceMachPort io_surface_mach_port;
#endif
diff --git a/ui/gfx/ca_layer_result.h b/ui/gfx/ca_layer_result.h
new file mode 100644
index 0000000..8a1bd1f
--- /dev/null
+++ b/ui/gfx/ca_layer_result.h
@@ -0,0 +1,58 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_CA_LAYER_RESULT_H_
+#define UI_GFX_CA_LAYER_RESULT_H_
+
+namespace gfx {
+
+// This is the result of ProcessForCALayerOverlays() and is for macOS only.
+// This enum is used for histogram states and should only have new values added
+// to the end before COUNT. tools/metrics/histograms/enums.xml should be updated
+// together.
+// All changes made to enum CALayerResult should be added to
+// ui/gfx/mojom/ca_layer_result.mojom.
+
+enum CALayerResult {
+ kCALayerSuccess = 0,
+ kCALayerFailedUnknown = 1,
+ // kCALayerFailedIOSurfaceNotCandidate = 2,
+ kCALayerFailedStreamVideoNotCandidate = 3,
+ // kCALayerFailedStreamVideoTransform = 4,
+ kCALayerFailedTextureNotCandidate = 5,
+ // kCALayerFailedTextureYFlipped = 6,
+ kCALayerFailedTileNotCandidate = 7,
+ kCALayerFailedQuadBlendMode = 8,
+ // kCALayerFailedQuadTransform = 9,
+ kCALayerFailedQuadClipping = 10,
+ kCALayerFailedDebugBoarder = 11,
+ kCALayerFailedPictureContent = 12,
+ // kCALayerFailedRenderPass = 13,
+ kCALayerFailedSurfaceContent = 14,
+ // kCALayerFailedYUVVideoContent = 15,
+ kCALayerFailedDifferentClipSettings = 16,
+ kCALayerFailedDifferentVertexOpacities = 17,
+ // kCALayerFailedRenderPassfilterScale = 18,
+ kCALayerFailedRenderPassBackdropFilters = 19,
+ kCALayerFailedRenderPassPassMask = 20,
+ kCALayerFailedRenderPassFilterOperation = 21,
+ kCALayerFailedRenderPassSortingContextId = 22,
+ kCALayerFailedTooManyRenderPassDrawQuads = 23,
+ // kCALayerFailedQuadRoundedCorner = 24,
+ // kCALayerFailedQuadRoundedCornerClipMismatch = 25,
+ kCALayerFailedQuadRoundedCornerNotUniform = 26,
+ kCALayerFailedTooManyQuads = 27,
+ kCALayerFailedYUVNotCandidate = 28,
+ kCALayerFailedYUVTexcoordMismatch = 29,
+ kCALayerFailedYUVInvalidPlanes = 30,
+ kCALayerFailedCopyRequests = 31,
+ kCALayerFailedOverlayDisabled = 32,
+ kCALayerFailedVideoCaptureEnabled = 33,
+ kCALayerUnknownDidNotSwap = 34, // For gpu_bench_marking only
+ kCALayerUnknownNoWidget = 35, // For gpu_bench_marking only
+ kMaxValue = kCALayerUnknownNoWidget,
+};
+} // namespace gfx
+
+#endif // UI_GFX_CA_LAYER_RESULT_H_
diff --git a/ui/gfx/canvas.cc b/ui/gfx/canvas.cc
index b462f08..4f6651e 100644
--- a/ui/gfx/canvas.cc
+++ b/ui/gfx/canvas.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -26,6 +26,7 @@
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/geometry/transform.h"
+#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/scoped_canvas.h"
#include "ui/gfx/skia_paint_util.h"
#include "ui/gfx/switches.h"
@@ -110,16 +111,15 @@
}
void Canvas::SaveLayerAlpha(uint8_t alpha) {
- canvas_->saveLayerAlpha(NULL, alpha);
+ canvas_->saveLayerAlphaf(alpha / 255.0f);
}
void Canvas::SaveLayerAlpha(uint8_t alpha, const Rect& layer_bounds) {
- SkRect bounds(RectToSkRect(layer_bounds));
- canvas_->saveLayerAlpha(&bounds, alpha);
+ canvas_->saveLayerAlphaf(RectToSkRect(layer_bounds), alpha / 255.0f);
}
void Canvas::SaveLayerWithFlags(const cc::PaintFlags& flags) {
- canvas_->saveLayer(nullptr /* bounds */, &flags);
+ canvas_->saveLayer(flags);
}
void Canvas::Restore() {
@@ -161,7 +161,7 @@
}
void Canvas::DrawColor(SkColor color, SkBlendMode mode) {
- canvas_->drawColor(color, mode);
+ canvas_->drawColor(SkColor4f::FromColor(color), mode);
}
void Canvas::FillRect(const Rect& rect, SkColor color) {
@@ -300,7 +300,7 @@
void Canvas::DrawImageInt(const ImageSkia& image, int x, int y, uint8_t a) {
cc::PaintFlags flags;
- flags.setAlpha(a);
+ flags.setAlphaf(a / 255.0f);
DrawImageInt(image, x, y, flags);
}
@@ -318,7 +318,7 @@
SkFloatToScalar(1.0f / bitmap_scale));
canvas_->translate(SkFloatToScalar(std::round(x * bitmap_scale)),
SkFloatToScalar(std::round(y * bitmap_scale)));
- canvas_->saveLayer(nullptr, &flags);
+ canvas_->saveLayer(flags);
canvas_->drawPicture(image_rep.GetPaintRecord());
canvas_->restore();
}
@@ -394,8 +394,12 @@
void Canvas::DrawSkottie(scoped_refptr<cc::SkottieWrapper> skottie,
const Rect& dst,
- float t) {
- canvas_->drawSkottie(std::move(skottie), RectToSkRect(dst), t);
+ float t,
+ cc::SkottieFrameDataMap images,
+ const cc::SkottieColorMap& color_map,
+ cc::SkottieTextPropertyValueMap text_map) {
+ canvas_->drawSkottie(std::move(skottie), RectToSkRect(dst), t,
+ std::move(images), color_map, std::move(text_map));
}
void Canvas::DrawStringRect(const std::u16string& text,
@@ -467,7 +471,7 @@
}
void Canvas::Transform(const gfx::Transform& transform) {
- canvas_->concat(SkMatrix(transform.matrix()));
+ canvas_->concat(TransformToSkM44(transform));
}
SkBitmap Canvas::GetBitmap() const {
diff --git a/ui/gfx/canvas.h b/ui/gfx/canvas.h
index 207a44e..8b20047 100644
--- a/ui/gfx/canvas.h
+++ b/ui/gfx/canvas.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,10 +11,13 @@
#include <string>
#include <vector>
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
#include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_flags.h"
#include "cc/paint/skia_paint_canvas.h"
+#include "cc/paint/skottie_color_map.h"
+#include "cc/paint/skottie_frame_data.h"
+#include "cc/paint/skottie_text_property_value.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/native_widget_types.h"
@@ -103,8 +106,6 @@
// Recreates the backing platform canvas with DIP |size| and |image_scale_|.
// If the canvas is not opaque, it is explicitly cleared.
- // This method is public so that canvas_skia_paint can recreate the platform
- // canvas after having initialized the canvas.
// TODO(pkotwicz): Push the image_scale into skia::PlatformCanvas such that
// this method can be private.
void RecreateBackingCanvas(const Size& size,
@@ -359,10 +360,15 @@
// Draws the frame of the |skottie| animation specified by the normalized time
// instant t [0->first frame .. 1->last frame] onto the region corresponded by
- // |dst| in the canvas.
+ // |dst| in the canvas. |images| is a map from asset id to the corresponding
+ // image to use when rendering this frame; it may be empty if this animation
+ // frame does not contain any images in it.
void DrawSkottie(scoped_refptr<cc::SkottieWrapper> skottie,
const Rect& dst,
- float t);
+ float t,
+ cc::SkottieFrameDataMap images,
+ const cc::SkottieColorMap& color_map,
+ cc::SkottieTextPropertyValueMap text_map);
// Draws text with the specified color, fonts and location. The text is
// aligned to the left, vertically centered, clipped to the region. If the
@@ -462,7 +468,7 @@
// there but bitmap_ and owned_canvas_ will not exist.
absl::optional<SkBitmap> bitmap_;
absl::optional<cc::SkiaPaintCanvas> owned_canvas_;
- cc::PaintCanvas* canvas_;
+ raw_ptr<cc::PaintCanvas> canvas_;
};
} // namespace gfx
diff --git a/ui/gfx/canvas_paint_mac.h b/ui/gfx/canvas_paint_mac.h
deleted file mode 100644
index 1623b4ba..0000000
--- a/ui/gfx/canvas_paint_mac.h
+++ /dev/null
@@ -1,58 +0,0 @@
-
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_CANVAS_PAINT_MAC_H_
-#define UI_GFX_CANVAS_PAINT_MAC_H_
-
-#include "skia/ext/platform_canvas.h"
-#include "ui/gfx/canvas.h"
-
-#import <Cocoa/Cocoa.h>
-
-namespace gfx {
-
-// A class designed to translate skia painting into a region to the current
-// graphics context. On construction, it will set up a context for painting
-// into, and on destruction, it will commit it to the current context.
-// Note: The created context is always inialized to (0, 0, 0, 0).
-class GFX_EXPORT CanvasSkiaPaint : public Canvas {
- public:
- // This constructor assumes the result is opaque.
- explicit CanvasSkiaPaint(NSRect dirtyRect);
- CanvasSkiaPaint(NSRect dirtyRect, bool opaque);
- ~CanvasSkiaPaint() override;
-
- // If true, the data painted into the CanvasSkiaPaint is blended onto the
- // current context, else it is copied.
- void set_composite_alpha(bool composite_alpha) {
- composite_alpha_ = composite_alpha;
- }
-
- // Returns true if the invalid region is empty. The caller should call this
- // function to determine if anything needs painting.
- bool is_empty() const {
- return NSIsEmptyRect(rectangle_);
- }
-
- const NSRect& rectangle() const {
- return rectangle_;
- }
-
- private:
- void Init(bool opaque);
-
- NSRect rectangle_;
- // See description above setter.
- bool composite_alpha_;
-
- // Disallow copy and assign.
- CanvasSkiaPaint(const CanvasSkiaPaint&);
- CanvasSkiaPaint& operator=(const CanvasSkiaPaint&);
-};
-
-} // namespace gfx
-
-
-#endif // UI_GFX_CANVAS_PAINT_MAC_H_
diff --git a/ui/gfx/canvas_paint_mac.mm b/ui/gfx/canvas_paint_mac.mm
deleted file mode 100644
index cf22d3a..0000000
--- a/ui/gfx/canvas_paint_mac.mm
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/mac/mac_util.h"
-#include "third_party/skia/include/utils/mac/SkCGUtils.h"
-#include "ui/gfx/canvas_paint_mac.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace gfx {
-
-CanvasSkiaPaint::CanvasSkiaPaint(NSRect dirtyRect)
- : rectangle_(dirtyRect),
- composite_alpha_(false) {
- Init(true);
-}
-
-CanvasSkiaPaint::CanvasSkiaPaint(NSRect dirtyRect, bool opaque)
- : rectangle_(dirtyRect),
- composite_alpha_(false) {
- Init(opaque);
-}
-
-CanvasSkiaPaint::~CanvasSkiaPaint() {
- if (!is_empty()) {
- sk_canvas()->restoreToCount(1);
-
- // Blit the dirty rect to the current context.
- CGImageRef image = SkCreateCGImageRefWithColorspace(
- GetBitmap(), base::mac::GetSystemColorSpace());
- CGRect dest_rect = NSRectToCGRect(rectangle_);
-
- CGContextRef destination_context =
- (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
- CGContextSaveGState(destination_context);
- CGContextSetBlendMode(
- destination_context,
- composite_alpha_ ? kCGBlendModeNormal : kCGBlendModeCopy);
-
- if ([[NSGraphicsContext currentContext] isFlipped]) {
- // Mirror context on the target's rect middle scanline.
- CGContextTranslateCTM(destination_context, 0.0, NSMidY(rectangle_));
- CGContextScaleCTM(destination_context, 1.0, -1.0);
- CGContextTranslateCTM(destination_context, 0.0, -NSMidY(rectangle_));
- }
-
- CGContextDrawImage(destination_context, dest_rect, image);
- CGContextRestoreGState(destination_context);
-
- CFRelease(image);
- }
-}
-
-void CanvasSkiaPaint::Init(bool opaque) {
- CGContextRef destination_context =
- (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
- CGRect scaled_unit_rect = CGContextConvertRectToDeviceSpace(
- destination_context, CGRectMake(0, 0, 1, 1));
- // Assume that the x scale and the y scale are the same.
- CGFloat scale = scaled_unit_rect.size.width;
-
- gfx::Size size(NSWidth(rectangle_), NSHeight(rectangle_));
- RecreateBackingCanvas(size, scale, opaque);
- cc::PaintCanvas* canvas = sk_canvas();
- canvas->clear(SK_ColorTRANSPARENT);
-
- // Need to translate so that the dirty region appears at the origin of the
- // surface.
- canvas->translate(-SkDoubleToScalar(NSMinX(rectangle_)),
- -SkDoubleToScalar(NSMinY(rectangle_)));
-}
-
-} // namespace skia
-
-
diff --git a/ui/gfx/canvas_skia.cc b/ui/gfx/canvas_skia.cc
index f0ee5bf..c07c736 100644
--- a/ui/gfx/canvas_skia.cc
+++ b/ui/gfx/canvas_skia.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -187,15 +187,6 @@
int line_padding = 0;
const int line_height = render_text->GetStringSize().height();
- // TODO(msw|asvitkine): Center Windows multi-line text: crbug.com/107357
-#if !defined(OS_WIN)
- if (i == 0) {
- // TODO(msw|asvitkine): Support multi-line text with varied heights.
- const int text_height = strings.size() * line_height - line_padding;
- rect += Vector2d(0, (text_bounds.height() - text_height) / 2);
- }
-#endif
-
rect.set_height(line_height - line_padding);
if (range.IsValid())
@@ -209,7 +200,7 @@
Range range = StripAcceleratorChars(flags, &adjusted_text);
bool elide_text = ((flags & NO_ELLIPSIS) == 0);
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
// On Linux, eliding really means fading the end of the string. But only
// for LTR text. RTL text is still elided (on the left) with "...".
if (elide_text) {
diff --git a/ui/gfx/canvas_skia_paint.h b/ui/gfx/canvas_skia_paint.h
deleted file mode 100644
index 01b366a..0000000
--- a/ui/gfx/canvas_skia_paint.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_CANVAS_SKIA_PAINT_H_
-#define UI_GFX_CANVAS_SKIA_PAINT_H_
-
-// This file provides an easy way to include the appropriate CanvasPaint
-// header file on your platform.
-
-#if defined(__APPLE__)
-#include "ui/gfx/canvas_paint_mac.h"
-#else
-#error "No canvas paint for this platform"
-#endif
-
-#endif // UI_GFX_CANVAS_SKIA_PAINT_H_
diff --git a/ui/gfx/canvas_unittest.cc b/ui/gfx/canvas_unittest.cc
index c2e1615..d8a1d2e 100644
--- a/ui/gfx/canvas_unittest.cc
+++ b/ui/gfx/canvas_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/client_native_pixmap.h b/ui/gfx/client_native_pixmap.h
index 07cee49..510100a 100644
--- a/ui/gfx/client_native_pixmap.h
+++ b/ui/gfx/client_native_pixmap.h
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/client_native_pixmap_factory.h b/ui/gfx/client_native_pixmap_factory.h
index 96aede0..8d7d5fc 100644
--- a/ui/gfx/client_native_pixmap_factory.h
+++ b/ui/gfx/client_native_pixmap_factory.h
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,7 +9,6 @@
#include <vector>
#include "base/files/scoped_file.h"
-#include "base/macros.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/client_native_pixmap.h"
#include "ui/gfx/gfx_export.h"
@@ -20,14 +19,16 @@
class Size;
// The Ozone interface allows external implementations to hook into Chromium to
-// provide a client pixmap for non-GPU processes.
+// provide a client pixmap for non-GPU processes (though ClientNativePixmap
+// instances created using this interface can be used in the GPU process).
class GFX_EXPORT ClientNativePixmapFactory {
public:
virtual ~ClientNativePixmapFactory() {}
- // Import the native pixmap from |handle| to be used in non-GPU processes.
- // Implementations must verify that the buffer in |handle| fits an image of
- // the specified |size| and |format|. Otherwise nullptr is returned.
+ // Import the native pixmap from |handle|. Implementations must verify that
+ // the buffer in |handle| fits an image of the specified |size| and |format|.
+ // Otherwise nullptr is returned. Note that a |handle| with no planes may or
+ // may not be considered valid depending on the implementation.
virtual std::unique_ptr<ClientNativePixmap> ImportFromHandle(
gfx::NativePixmapHandle handle,
const gfx::Size& size,
diff --git a/ui/gfx/codec/BUILD.gn b/ui/gfx/codec/BUILD.gn
index 44401dc..34ea362 100644
--- a/ui/gfx/codec/BUILD.gn
+++ b/ui/gfx/codec/BUILD.gn
@@ -1,7 +1,8 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
+# Copyright 2017 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/features.gni")
import("//build/config/ui.gni")
component("codec") {
@@ -26,7 +27,7 @@
"//ui/gfx/geometry",
]
- if (is_ios) {
+ if (!use_blink) {
sources -= [
"jpeg_codec.cc",
"jpeg_codec.h",
diff --git a/ui/gfx/codec/codec_export.h b/ui/gfx/codec/codec_export.h
index c56a070..76b3144 100644
--- a/ui/gfx/codec/codec_export.h
+++ b/ui/gfx/codec/codec_export.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/codec/jpeg_codec.cc b/ui/gfx/codec/jpeg_codec.cc
index d1fbdd7..62005fc 100644
--- a/ui/gfx/codec/jpeg_codec.cc
+++ b/ui/gfx/codec/jpeg_codec.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/codec/jpeg_codec.h b/ui/gfx/codec/jpeg_codec.h
index 14f8879..8f60bda 100644
--- a/ui/gfx/codec/jpeg_codec.h
+++ b/ui/gfx/codec/jpeg_codec.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/codec/jpeg_codec_unittest.cc b/ui/gfx/codec/jpeg_codec_unittest.cc
index 2d0748e..9f1bee9 100644
--- a/ui/gfx/codec/jpeg_codec_unittest.cc
+++ b/ui/gfx/codec/jpeg_codec_unittest.cc
@@ -1,19 +1,19 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/gfx/codec/jpeg_codec.h"
+
#include <math.h>
#include <stddef.h>
#include <stdint.h>
#include "base/barrier_closure.h"
-#include "base/cxx17_backports.h"
#include "base/run_loop.h"
#include "base/task/thread_pool.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/codec/jpeg_codec.h"
namespace {
@@ -179,7 +179,7 @@
std::vector<unsigned char> output;
int outw, outh;
JPEGCodec::Decode(kTopSitesMigrationTestImage,
- base::size(kTopSitesMigrationTestImage),
+ std::size(kTopSitesMigrationTestImage),
JPEGCodec::FORMAT_RGBA, &output, &outw, &outh);
}
diff --git a/ui/gfx/codec/png_codec.cc b/ui/gfx/codec/png_codec.cc
index 0782945..2cc1c43 100644
--- a/ui/gfx/codec/png_codec.cc
+++ b/ui/gfx/codec/png_codec.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,7 +7,8 @@
#include <stdint.h>
#include "base/logging.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ptr_exclusion.h"
#include "base/notreached.h"
#include "base/strings/string_util.h"
#include "third_party/libpng/png.h"
@@ -64,7 +65,7 @@
int output_channels;
// An incoming SkBitmap to write to. If NULL, we write to output instead.
- SkBitmap* bitmap;
+ raw_ptr<SkBitmap> bitmap;
// Used during the reading of an SkBitmap. Defaults to true until we see a
// pixel with anything other than an alpha of 255.
@@ -72,7 +73,7 @@
// The other way to decode output, where we write into an intermediary buffer
// instead of directly to an SkBitmap.
- std::vector<unsigned char>* output;
+ raw_ptr<std::vector<unsigned char>> output;
// Size of the image, set in the info callback.
int width;
@@ -219,7 +220,11 @@
png_read_update_info(png_ptr, info_ptr);
if (state->bitmap) {
- state->bitmap->allocN32Pixels(state->width, state->height);
+ if (!state->bitmap->tryAllocN32Pixels(state->width, state->height)) {
+ png_error(png_ptr, "Could not allocate bitmap.");
+ NOTREACHED();
+ return;
+ }
} else if (state->output) {
state->output->resize(
state->width * state->output_channels * state->height);
@@ -291,8 +296,12 @@
return true;
}
- png_struct* png_ptr_;
- png_info* info_ptr_;
+ // This field is not a raw_ptr<> because it was filtered by the rewriter for:
+ // #addr-of
+ RAW_PTR_EXCLUSION png_struct* png_ptr_;
+ // This field is not a raw_ptr<> because it was filtered by the rewriter for:
+ // #addr-of
+ RAW_PTR_EXCLUSION png_info* info_ptr_;
};
// Holds png struct and info ensuring the proper destruction.
@@ -308,8 +317,12 @@
png_destroy_write_struct(&png_ptr_, &info_ptr_);
}
- png_struct* png_ptr_;
- png_info* info_ptr_;
+ // This field is not a raw_ptr<> because it was filtered by the rewriter for:
+ // #addr-of
+ RAW_PTR_EXCLUSION png_struct* png_ptr_;
+ // This field is not a raw_ptr<> because it was filtered by the rewriter for:
+ // #addr-of
+ RAW_PTR_EXCLUSION png_info* info_ptr_;
};
// Libpng user error and warning functions which allows us to print libpng
@@ -403,8 +416,8 @@
namespace {
-static void AddComments(SkPngEncoder::Options& options,
- const std::vector<PNGCodec::Comment>& comments) {
+void AddComments(SkPngEncoder::Options& options,
+ const std::vector<PNGCodec::Comment>& comments) {
std::vector<const char*> comment_pointers;
std::vector<size_t> comment_sizes;
for (const auto& comment : comments) {
@@ -418,26 +431,28 @@
static_cast<int>(comment_pointers.size()));
}
-} // namespace
-
-static bool EncodeSkPixmap(const SkPixmap& src,
- const std::vector<PNGCodec::Comment>& comments,
- std::vector<unsigned char>* output,
- int zlib_level) {
+bool EncodeSkPixmap(const SkPixmap& src,
+ const std::vector<PNGCodec::Comment>& comments,
+ std::vector<unsigned char>* output,
+ int zlib_level,
+ bool disable_filters) {
output->clear();
VectorWStream dst(output);
SkPngEncoder::Options options;
AddComments(options, comments);
options.fZLibLevel = zlib_level;
+ if (disable_filters)
+ options.fFilterFlags = SkPngEncoder::FilterFlag::kNone;
return SkPngEncoder::Encode(&dst, src, options);
}
-static bool EncodeSkPixmap(const SkPixmap& src,
- bool discard_transparency,
- const std::vector<PNGCodec::Comment>& comments,
- std::vector<unsigned char>* output,
- int zlib_level) {
+bool EncodeSkPixmap(const SkPixmap& src,
+ bool discard_transparency,
+ const std::vector<PNGCodec::Comment>& comments,
+ std::vector<unsigned char>* output,
+ int zlib_level,
+ bool disable_filters) {
if (discard_transparency) {
SkImageInfo opaque_info = src.info().makeAlphaType(kOpaque_SkAlphaType);
SkBitmap copy;
@@ -454,11 +469,28 @@
src.readPixels(opaque_info.makeAlphaType(kUnpremul_SkAlphaType),
opaque_pixmap.writable_addr(), opaque_pixmap.rowBytes());
DCHECK(success);
- return EncodeSkPixmap(opaque_pixmap, comments, output, zlib_level);
+ return EncodeSkPixmap(opaque_pixmap, comments, output, zlib_level,
+ disable_filters);
}
- return EncodeSkPixmap(src, comments, output, zlib_level);
+ return EncodeSkPixmap(src, comments, output, zlib_level, disable_filters);
}
+bool EncodeSkBitmap(const SkBitmap& input,
+ bool discard_transparency,
+ std::vector<unsigned char>* output,
+ int zlib_level,
+ bool disable_filters) {
+ SkPixmap src;
+ if (!input.peekPixels(&src)) {
+ return false;
+ }
+ return EncodeSkPixmap(src, discard_transparency,
+ std::vector<PNGCodec::Comment>(), output, zlib_level,
+ disable_filters);
+}
+
+} // namespace
+
// static
bool PNGCodec::Encode(const unsigned char* input,
ColorFormat format,
@@ -486,19 +518,7 @@
SkImageInfo::Make(size.width(), size.height(), colorType, alphaType);
SkPixmap src(info, input, row_byte_width);
return EncodeSkPixmap(src, discard_transparency, comments, output,
- DEFAULT_ZLIB_COMPRESSION);
-}
-
-static bool EncodeSkBitmap(const SkBitmap& input,
- bool discard_transparency,
- std::vector<unsigned char>* output,
- int zlib_level) {
- SkPixmap src;
- if (!input.peekPixels(&src)) {
- return false;
- }
- return EncodeSkPixmap(src, discard_transparency,
- std::vector<PNGCodec::Comment>(), output, zlib_level);
+ DEFAULT_ZLIB_COMPRESSION, /* disable_filters= */ false);
}
// static
@@ -506,7 +526,7 @@
bool discard_transparency,
std::vector<unsigned char>* output) {
return EncodeSkBitmap(input, discard_transparency, output,
- DEFAULT_ZLIB_COMPRESSION);
+ DEFAULT_ZLIB_COMPRESSION, /* disable_filters= */ false);
}
// static
@@ -518,14 +538,15 @@
.makeAlphaType(kOpaque_SkAlphaType);
SkPixmap src(info, input.getAddr(0, 0), input.rowBytes());
return EncodeSkPixmap(src, std::vector<PNGCodec::Comment>(), output,
- DEFAULT_ZLIB_COMPRESSION);
+ DEFAULT_ZLIB_COMPRESSION, /* disable_filters= */ false);
}
// static
bool PNGCodec::FastEncodeBGRASkBitmap(const SkBitmap& input,
bool discard_transparency,
std::vector<unsigned char>* output) {
- return EncodeSkBitmap(input, discard_transparency, output, Z_BEST_SPEED);
+ return EncodeSkBitmap(input, discard_transparency, output, Z_BEST_SPEED,
+ /* disable_filters= */ true);
}
PNGCodec::Comment::Comment(const std::string& k, const std::string& t)
diff --git a/ui/gfx/codec/png_codec.h b/ui/gfx/codec/png_codec.h
index f5d4eb9..8bba9b5 100644
--- a/ui/gfx/codec/png_codec.h
+++ b/ui/gfx/codec/png_codec.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,7 +10,6 @@
#include <string>
#include <vector>
-#include "base/macros.h"
#include "ui/gfx/codec/codec_export.h"
class SkBitmap;
diff --git a/ui/gfx/codec/png_codec_unittest.cc b/ui/gfx/codec/png_codec_unittest.cc
index 083c6a8..7644ddd 100644
--- a/ui/gfx/codec/png_codec_unittest.cc
+++ b/ui/gfx/codec/png_codec_unittest.cc
@@ -1,22 +1,23 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/gfx/codec/png_codec.h"
+
#include <stddef.h>
#include <stdint.h>
-#include <algorithm>
#include <cmath>
-#include "base/cxx17_backports.h"
+#include "base/check.h"
#include "base/logging.h"
+#include "base/ranges/algorithm.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libpng/png.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColorPriv.h"
#include "third_party/skia/include/core/SkUnPreMultiply.h"
#include "third_party/zlib/zlib.h"
-#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/skia_util.h"
@@ -922,15 +923,9 @@
const unsigned char kExpected3[] =
"\x00\x00\x00\x18tEXthave some\x00spaces in both\x8d\x69\x34\x2d";
- EXPECT_NE(std::search(encoded.begin(), encoded.end(), kExpected1,
- kExpected1 + base::size(kExpected1)),
- encoded.end());
- EXPECT_NE(std::search(encoded.begin(), encoded.end(), kExpected2,
- kExpected2 + base::size(kExpected2)),
- encoded.end());
- EXPECT_NE(std::search(encoded.begin(), encoded.end(), kExpected3,
- kExpected3 + base::size(kExpected3)),
- encoded.end());
+ EXPECT_NE(base::ranges::search(encoded, kExpected1), encoded.end());
+ EXPECT_NE(base::ranges::search(encoded, kExpected2), encoded.end());
+ EXPECT_NE(base::ranges::search(encoded, kExpected3), encoded.end());
}
TEST(PNGCodec, EncodeDecodeWithVaryingCompressionLevels) {
diff --git a/ui/gfx/codec/vector_wstream.cc b/ui/gfx/codec/vector_wstream.cc
index 6d485a2..64bd71d 100644
--- a/ui/gfx/codec/vector_wstream.cc
+++ b/ui/gfx/codec/vector_wstream.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/codec/vector_wstream.h b/ui/gfx/codec/vector_wstream.h
index b740e7e..184b45d 100644
--- a/ui/gfx/codec/vector_wstream.h
+++ b/ui/gfx/codec/vector_wstream.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,6 +10,7 @@
#include <vector>
#include "base/check_op.h"
+#include "base/memory/raw_ptr.h"
#include "third_party/skia/include/core/SkStream.h"
namespace gfx {
@@ -28,7 +29,7 @@
private:
// Does not have ownership.
- std::vector<unsigned char>* dst_;
+ raw_ptr<std::vector<unsigned char>> dst_;
};
} // namespace gfx
diff --git a/ui/gfx/codec/webp_codec.cc b/ui/gfx/codec/webp_codec.cc
index d325fe1..e762e43 100644
--- a/ui/gfx/codec/webp_codec.cc
+++ b/ui/gfx/codec/webp_codec.cc
@@ -1,10 +1,11 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/codec/webp_codec.h"
-#include "third_party/skia/include/encode/SkWebpEncoder.h"
+#include <vector>
+
#include "ui/gfx/codec/vector_wstream.h"
namespace gfx {
@@ -33,4 +34,33 @@
return WebpCodec::Encode(pixmap, quality, output);
}
+absl::optional<std::vector<uint8_t>> WebpCodec::EncodeAnimated(
+ const std::vector<SkEncoder::Frame>& frames,
+ const SkWebpEncoder::Options& options) {
+ std::vector<uint8_t> output;
+ VectorWStream dst(&output);
+
+ if (!SkWebpEncoder::EncodeAnimated(&dst, frames, options)) {
+ return absl::nullopt;
+ }
+
+ return output;
+}
+
+absl::optional<std::vector<uint8_t>> WebpCodec::EncodeAnimated(
+ const std::vector<Frame>& frames,
+ const SkWebpEncoder::Options& options) {
+ std::vector<SkEncoder::Frame> pixmap_frames;
+ for (const auto& frame : frames) {
+ SkEncoder::Frame pixmap_frame;
+ if (!frame.bitmap.peekPixels(&pixmap_frame.pixmap)) {
+ return absl::nullopt;
+ }
+ pixmap_frame.duration = frame.duration;
+ pixmap_frames.push_back(pixmap_frame);
+ }
+
+ return WebpCodec::EncodeAnimated(pixmap_frames, options);
+}
+
} // namespace gfx
diff --git a/ui/gfx/codec/webp_codec.h b/ui/gfx/codec/webp_codec.h
index ce4e0aa..9c8d6df 100644
--- a/ui/gfx/codec/webp_codec.h
+++ b/ui/gfx/codec/webp_codec.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,9 +7,11 @@
#include <vector>
-#include "base/macros.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkPixmap.h"
+#include "third_party/skia/include/encode/SkEncoder.h"
+#include "third_party/skia/include/encode/SkWebpEncoder.h"
#include "ui/gfx/codec/codec_export.h"
class SkBitmap;
@@ -23,6 +25,13 @@
// supports lossy encoding.
class CODEC_EXPORT WebpCodec {
public:
+ struct Frame {
+ // Bitmap of the frame.
+ SkBitmap bitmap;
+ // Duration of the frame in milliseconds.
+ int duration;
+ };
+
WebpCodec(const WebpCodec&) = delete;
WebpCodec& operator=(const WebpCodec&) = delete;
@@ -49,6 +58,18 @@
static bool Encode(const SkBitmap& input,
int quality,
std::vector<unsigned char>* output);
+
+ // Encodes the pixmap 'frames' as an animated WebP image. Returns the encoded
+ // data on success, or absl::nullopt on failure.
+ static absl::optional<std::vector<uint8_t>> EncodeAnimated(
+ const std::vector<SkEncoder::Frame>& frames,
+ const SkWebpEncoder::Options& options);
+
+ // Encodes the bitmap 'frames' as an animated WebP image. Returns the encoded
+ // data on success, or absl::nullopt on failure.
+ static absl::optional<std::vector<uint8_t>> EncodeAnimated(
+ const std::vector<Frame>& frames,
+ const SkWebpEncoder::Options& options);
};
} // namespace gfx
diff --git a/ui/gfx/color_analysis.cc b/ui/gfx/color_analysis.cc
index 8a74f0b..86eeb7a 100644
--- a/ui/gfx/color_analysis.cc
+++ b/ui/gfx/color_analysis.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -15,10 +15,10 @@
#include <unordered_map>
#include <vector>
-#include "base/bind.h"
-#include "base/callback.h"
#include "base/check_op.h"
-#include "base/cxx17_backports.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
+#include "base/memory/raw_ptr_exclusion.h"
#include "base/notreached.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkUnPreMultiply.h"
@@ -301,7 +301,9 @@
// The set of colors of which this box captures a subset. This vector is not
// owned but may be modified during the split operation.
- std::vector<SkColor>* color_space_;
+ // This field is not a raw_ptr<> because it was filtered by the rewriter for:
+ // #constexpr-ctor-field-initializer
+ RAW_PTR_EXCLUSION std::vector<SkColor>* color_space_;
// The range of indexes into |color_space_| that are part of this box.
gfx::Range color_range_;
@@ -639,7 +641,7 @@
// we can end up creating a larger buffer than we have data for, and the end
// of the buffer will remain uninitialized after we copy/UnPreMultiply the
// image data into it).
- height = base::clamp(height, 0, bitmap.height());
+ height = std::clamp(height, 0, bitmap.height());
// SkBitmap uses pre-multiplied alpha but the KMean clustering function
// above uses non-pre-multiplied alpha. Transform the bitmap before we
@@ -816,152 +818,4 @@
filter.is_null() ? base::BindRepeating(&IsInterestingColor) : filter);
}
-gfx::Matrix3F ComputeColorCovariance(const SkBitmap& bitmap) {
- // First need basic stats to normalize each channel separately.
- gfx::Matrix3F covariance = gfx::Matrix3F::Zeros();
- if (!bitmap.getPixels())
- return covariance;
-
- // Assume ARGB_8888 format.
- DCHECK(bitmap.colorType() == kN32_SkColorType);
-
- int64_t r_sum = 0;
- int64_t g_sum = 0;
- int64_t b_sum = 0;
- int64_t rr_sum = 0;
- int64_t gg_sum = 0;
- int64_t bb_sum = 0;
- int64_t rg_sum = 0;
- int64_t rb_sum = 0;
- int64_t gb_sum = 0;
-
- for (int y = 0; y < bitmap.height(); ++y) {
- SkPMColor* current_color = static_cast<uint32_t*>(bitmap.getAddr32(0, y));
- for (int x = 0; x < bitmap.width(); ++x, ++current_color) {
- SkColor c = SkUnPreMultiply::PMColorToColor(*current_color);
- SkColor r = SkColorGetR(c);
- SkColor g = SkColorGetG(c);
- SkColor b = SkColorGetB(c);
-
- r_sum += r;
- g_sum += g;
- b_sum += b;
- rr_sum += r * r;
- gg_sum += g * g;
- bb_sum += b * b;
- rg_sum += r * g;
- rb_sum += r * b;
- gb_sum += g * b;
- }
- }
-
- // Covariance (not normalized) is E(X*X.t) - m * m.t and this is how it
- // is calculated below.
- // Each row below represents a row of the matrix describing (co)variances
- // of R, G and B channels with (R, G, B)
- int pixel_n = bitmap.width() * bitmap.height();
- covariance.set(
- static_cast<float>(
- static_cast<double>(rr_sum) / pixel_n -
- static_cast<double>(r_sum * r_sum) / pixel_n / pixel_n),
- static_cast<float>(
- static_cast<double>(rg_sum) / pixel_n -
- static_cast<double>(r_sum * g_sum) / pixel_n / pixel_n),
- static_cast<float>(
- static_cast<double>(rb_sum) / pixel_n -
- static_cast<double>(r_sum * b_sum) / pixel_n / pixel_n),
- static_cast<float>(
- static_cast<double>(rg_sum) / pixel_n -
- static_cast<double>(r_sum * g_sum) / pixel_n / pixel_n),
- static_cast<float>(
- static_cast<double>(gg_sum) / pixel_n -
- static_cast<double>(g_sum * g_sum) / pixel_n / pixel_n),
- static_cast<float>(
- static_cast<double>(gb_sum) / pixel_n -
- static_cast<double>(g_sum * b_sum) / pixel_n / pixel_n),
- static_cast<float>(
- static_cast<double>(rb_sum) / pixel_n -
- static_cast<double>(r_sum * b_sum) / pixel_n / pixel_n),
- static_cast<float>(
- static_cast<double>(gb_sum) / pixel_n -
- static_cast<double>(g_sum * b_sum) / pixel_n / pixel_n),
- static_cast<float>(
- static_cast<double>(bb_sum) / pixel_n -
- static_cast<double>(b_sum * b_sum) / pixel_n / pixel_n));
- return covariance;
-}
-
-bool ApplyColorReduction(const SkBitmap& source_bitmap,
- const gfx::Vector3dF& color_transform,
- bool fit_to_range,
- SkBitmap* target_bitmap) {
- DCHECK(target_bitmap);
- DCHECK(source_bitmap.getPixels());
- DCHECK(target_bitmap->getPixels());
- DCHECK_EQ(kN32_SkColorType, source_bitmap.colorType());
- DCHECK_EQ(kAlpha_8_SkColorType, target_bitmap->colorType());
- DCHECK_EQ(source_bitmap.height(), target_bitmap->height());
- DCHECK_EQ(source_bitmap.width(), target_bitmap->width());
- DCHECK(!source_bitmap.empty());
-
- // Elements of color_transform are explicitly off-loaded to local values for
- // efficiency reasons. Note that in practice images may correspond to entire
- // tab captures.
- float t0 = 0.0;
- float tr = color_transform.x();
- float tg = color_transform.y();
- float tb = color_transform.z();
-
- if (fit_to_range) {
- // We will figure out min/max in a preprocessing step and adjust
- // actual_transform as required.
- float max_val = std::numeric_limits<float>::min();
- float min_val = std::numeric_limits<float>::max();
- for (int y = 0; y < source_bitmap.height(); ++y) {
- const SkPMColor* source_color_row = static_cast<SkPMColor*>(
- source_bitmap.getAddr32(0, y));
- for (int x = 0; x < source_bitmap.width(); ++x) {
- SkColor c = SkUnPreMultiply::PMColorToColor(source_color_row[x]);
- uint8_t r = SkColorGetR(c);
- uint8_t g = SkColorGetG(c);
- uint8_t b = SkColorGetB(c);
- float gray_level = tr * r + tg * g + tb * b;
- max_val = std::max(max_val, gray_level);
- min_val = std::min(min_val, gray_level);
- }
- }
-
- // Adjust the transform so that the result is scaling.
- float scale = 0.0;
- t0 = -min_val;
- if (max_val > min_val)
- scale = 255.0f / (max_val - min_val);
- t0 *= scale;
- tr *= scale;
- tg *= scale;
- tb *= scale;
- }
-
- for (int y = 0; y < source_bitmap.height(); ++y) {
- const SkPMColor* source_color_row = static_cast<SkPMColor*>(
- source_bitmap.getAddr32(0, y));
- uint8_t* target_color_row = target_bitmap->getAddr8(0, y);
- for (int x = 0; x < source_bitmap.width(); ++x) {
- SkColor c = SkUnPreMultiply::PMColorToColor(source_color_row[x]);
- uint8_t r = SkColorGetR(c);
- uint8_t g = SkColorGetG(c);
- uint8_t b = SkColorGetB(c);
-
- float gl = t0 + tr * r + tg * g + tb * b;
- if (gl < 0)
- gl = 0;
- if (gl > 0xFF)
- gl = 0xFF;
- target_color_row[x] = static_cast<uint8_t>(gl);
- }
- }
-
- return true;
-}
-
} // color_utils
diff --git a/ui/gfx/color_analysis.h b/ui/gfx/color_analysis.h
index fdaa8f3..f6a0b0e 100644
--- a/ui/gfx/color_analysis.h
+++ b/ui/gfx/color_analysis.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,12 +7,10 @@
#include <stdint.h>
-#include "base/callback_forward.h"
-#include "base/compiler_specific.h"
+#include "base/functional/callback_forward.h"
#include "base/memory/ref_counted.h"
#include "base/memory/ref_counted_memory.h"
#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/geometry/matrix3_f.h"
#include "ui/gfx/gfx_export.h"
class SkBitmap;
@@ -193,20 +191,6 @@
gfx::Rect* region,
ColorSwatchFilter filter);
-// Compute color covariance matrix for the input bitmap.
-GFX_EXPORT gfx::Matrix3F ComputeColorCovariance(const SkBitmap& bitmap);
-
-// Apply a color reduction transform defined by |color_transform| vector to
-// |source_bitmap|. The result is put into |target_bitmap|, which is expected
-// to be initialized to the required size and type (SkBitmap::kA8_Config).
-// If |fit_to_range|, result is transfored linearly to fit 0-0xFF range.
-// Otherwise, data is clipped.
-// Returns true if the target has been computed.
-GFX_EXPORT bool ApplyColorReduction(const SkBitmap& source_bitmap,
- const gfx::Vector3dF& color_transform,
- bool fit_to_range,
- SkBitmap* target_bitmap);
-
} // namespace color_utils
#endif // UI_GFX_COLOR_ANALYSIS_H_
diff --git a/ui/gfx/color_analysis_fuzzer.cc b/ui/gfx/color_analysis_fuzzer.cc
index ef2f6d8..55c3169 100644
--- a/ui/gfx/color_analysis_fuzzer.cc
+++ b/ui/gfx/color_analysis_fuzzer.cc
@@ -1,22 +1,15 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fuzzer/FuzzedDataProvider.h>
+#include <algorithm>
#include <vector>
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/color_analysis.h"
#include "ui/gfx/color_utils.h"
-double ConsumeDouble(FuzzedDataProvider* provider) {
- std::vector<uint8_t> v = provider->ConsumeBytes<uint8_t>(sizeof(double));
- if (v.size() == sizeof(double))
- return reinterpret_cast<double*>(v.data())[0];
-
- return 0;
-}
-
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
FuzzedDataProvider provider(data, size);
@@ -26,12 +19,17 @@
SkImageInfo info = SkImageInfo::MakeN32Premul(width, height);
size_t expected_size = info.computeMinByteSize();
- color_utils::HSL upper_bound = {ConsumeDouble(&provider),
- ConsumeDouble(&provider),
- ConsumeDouble(&provider)};
- color_utils::HSL lower_bound = {ConsumeDouble(&provider),
- ConsumeDouble(&provider),
- ConsumeDouble(&provider)};
+ const double lower_bound_hue = provider.ConsumeFloatingPointInRange(0.0, 1.0);
+ const double upper_bound_hue = provider.ConsumeFloatingPointInRange(
+ lower_bound_hue, lower_bound_hue + 1);
+ const double s1 = provider.ConsumeFloatingPointInRange(0.0, 1.0);
+ const double s2 = provider.ConsumeFloatingPointInRange(0.0, 1.0);
+ const double l1 = provider.ConsumeFloatingPointInRange(0.0, 1.0);
+ const double l2 = provider.ConsumeFloatingPointInRange(0.0, 1.0);
+ color_utils::HSL upper_bound = {upper_bound_hue, std::max(s1, s2),
+ std::max(l1, l2)};
+ color_utils::HSL lower_bound = {lower_bound_hue, std::min(s1, s2),
+ std::min(l1, l2)};
bool find_closest = provider.ConsumeBool();
diff --git a/ui/gfx/color_analysis_unittest.cc b/ui/gfx/color_analysis_unittest.cc
index bbf1e87..32d0387 100644
--- a/ui/gfx/color_analysis_unittest.cc
+++ b/ui/gfx/color_analysis_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,7 +10,7 @@
#include <exception>
#include <vector>
-#include "base/bind.h"
+#include "base/functional/bind.h"
#include "skia/ext/platform_canvas.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -145,26 +145,6 @@
return (abs(expected - static_cast<int>(channel)) <= 1);
}
-// Compute minimal and maximal graylevel (or alphalevel) of the input |bitmap|.
-// |bitmap| has to be allocated and configured to kA8_Config.
-void Calculate8bitBitmapMinMax(const SkBitmap& bitmap,
- uint8_t* min_gl,
- uint8_t* max_gl) {
- DCHECK(bitmap.getPixels());
- DCHECK_EQ(bitmap.colorType(), kAlpha_8_SkColorType);
- DCHECK(min_gl);
- DCHECK(max_gl);
- *min_gl = std::numeric_limits<uint8_t>::max();
- *max_gl = std::numeric_limits<uint8_t>::min();
- for (int y = 0; y < bitmap.height(); ++y) {
- uint8_t* current_color = bitmap.getAddr8(0, y);
- for (int x = 0; x < bitmap.width(); ++x, ++current_color) {
- *min_gl = std::min(*min_gl, *current_color);
- *max_gl = std::max(*max_gl, *current_color);
- }
- }
-}
-
class ColorAnalysisTest : public testing::Test {
};
@@ -357,146 +337,6 @@
EXPECT_TRUE(ChannelApproximatelyEqual(200, SkColorGetB(color)));
}
-TEST_F(ColorAnalysisTest, ComputeColorCovarianceTrivial) {
- SkBitmap bitmap;
- bitmap.setInfo(SkImageInfo::MakeN32Premul(100, 200));
-
- EXPECT_EQ(gfx::Matrix3F::Zeros(), ComputeColorCovariance(bitmap));
- bitmap.allocPixels();
- bitmap.eraseARGB(255, 50, 150, 200);
- gfx::Matrix3F covariance = ComputeColorCovariance(bitmap);
- // The answer should be all zeros.
- EXPECT_TRUE(covariance == gfx::Matrix3F::Zeros());
-}
-
-TEST_F(ColorAnalysisTest, ComputeColorCovarianceWithCanvas) {
- gfx::Canvas canvas(gfx::Size(250, 200), 1.0f, true);
- // The image consists of vertical stripes, with color bands set to 100
- // in overlapping stripes 150 pixels wide.
- canvas.FillRect(gfx::Rect(0, 0, 50, 200), SkColorSetRGB(100, 0, 0));
- canvas.FillRect(gfx::Rect(50, 0, 50, 200), SkColorSetRGB(100, 100, 0));
- canvas.FillRect(gfx::Rect(100, 0, 50, 200), SkColorSetRGB(100, 100, 100));
- canvas.FillRect(gfx::Rect(150, 0, 50, 200), SkColorSetRGB(0, 100, 100));
- canvas.FillRect(gfx::Rect(200, 0, 50, 200), SkColorSetRGB(0, 0, 100));
-
- gfx::Matrix3F covariance = ComputeColorCovariance(canvas.GetBitmap());
-
- gfx::Matrix3F expected_covariance = gfx::Matrix3F::Zeros();
- expected_covariance.set(2400, 400, -1600,
- 400, 2400, 400,
- -1600, 400, 2400);
- EXPECT_EQ(expected_covariance, covariance);
-}
-
-TEST_F(ColorAnalysisTest, ApplyColorReductionSingleColor) {
- // The test runs color reduction on a single-colot image, where results are
- // bound to be uninteresting. This is an important edge case, though.
- SkBitmap source, result;
- source.allocN32Pixels(300, 200);
- result.allocPixels(SkImageInfo::MakeA8(300, 200));
-
- source.eraseARGB(255, 50, 150, 200);
-
- gfx::Vector3dF transform(1.0f, .5f, 0.1f);
- // This transform, if not scaled, should result in GL=145.
- EXPECT_TRUE(ApplyColorReduction(source, transform, false, &result));
-
- uint8_t min_gl = 0;
- uint8_t max_gl = 0;
- Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
- EXPECT_EQ(145, min_gl);
- EXPECT_EQ(145, max_gl);
-
- // Now scan requesting rescale. Expect all 0.
- EXPECT_TRUE(ApplyColorReduction(source, transform, true, &result));
- Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
- EXPECT_EQ(0, min_gl);
- EXPECT_EQ(0, max_gl);
-
- // Test cliping to upper limit.
- transform.set_z(1.1f);
- EXPECT_TRUE(ApplyColorReduction(source, transform, false, &result));
- Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
- EXPECT_EQ(0xFF, min_gl);
- EXPECT_EQ(0xFF, max_gl);
-
- // Test cliping to upper limit.
- transform.Scale(-1.0f);
- EXPECT_TRUE(ApplyColorReduction(source, transform, false, &result));
- Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
- EXPECT_EQ(0x0, min_gl);
- EXPECT_EQ(0x0, max_gl);
-}
-
-TEST_F(ColorAnalysisTest, ApplyColorReductionBlackAndWhite) {
- // Check with images with multiple colors. This is really different only when
- // the result is scaled.
- gfx::Canvas canvas(gfx::Size(300, 200), 1.0f, true);
-
- // The image consists of vertical non-overlapping stripes 150 pixels wide.
- canvas.FillRect(gfx::Rect(0, 0, 150, 200), SkColorSetRGB(0, 0, 0));
- canvas.FillRect(gfx::Rect(150, 0, 150, 200), SkColorSetRGB(255, 255, 255));
- SkBitmap source = canvas.GetBitmap();
- SkBitmap result;
- result.allocPixels(SkImageInfo::MakeA8(300, 200));
-
- gfx::Vector3dF transform(1.0f, 0.5f, 0.1f);
- EXPECT_TRUE(ApplyColorReduction(source, transform, true, &result));
- uint8_t min_gl = 0;
- uint8_t max_gl = 0;
- Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
-
- EXPECT_EQ(0, min_gl);
- EXPECT_EQ(255, max_gl);
- EXPECT_EQ(min_gl, SkColorGetA(result.getColor(0, 0)));
- EXPECT_EQ(max_gl, SkColorGetA(result.getColor(299, 199)));
-
- // Reverse test.
- transform.Scale(-1.0f);
- EXPECT_TRUE(ApplyColorReduction(source, transform, true, &result));
- min_gl = 0;
- max_gl = 0;
- Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
-
- EXPECT_EQ(0, min_gl);
- EXPECT_EQ(255, max_gl);
- EXPECT_EQ(max_gl, SkColorGetA(result.getColor(0, 0)));
- EXPECT_EQ(min_gl, SkColorGetA(result.getColor(299, 199)));
-}
-
-TEST_F(ColorAnalysisTest, ApplyColorReductionMultiColor) {
- // Check with images with multiple colors. This is really different only when
- // the result is scaled.
- gfx::Canvas canvas(gfx::Size(300, 200), 1.0f, true);
-
- // The image consists of vertical non-overlapping stripes 100 pixels wide.
- canvas.FillRect(gfx::Rect(0, 0, 100, 200), SkColorSetRGB(100, 0, 0));
- canvas.FillRect(gfx::Rect(100, 0, 100, 200), SkColorSetRGB(0, 255, 0));
- canvas.FillRect(gfx::Rect(200, 0, 100, 200), SkColorSetRGB(0, 0, 128));
- SkBitmap source = canvas.GetBitmap();
- SkBitmap result;
- result.allocPixels(SkImageInfo::MakeA8(300, 200));
-
- gfx::Vector3dF transform(1.0f, 0.5f, 0.1f);
- EXPECT_TRUE(ApplyColorReduction(source, transform, false, &result));
- uint8_t min_gl = 0;
- uint8_t max_gl = 0;
- Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
- EXPECT_EQ(12, min_gl);
- EXPECT_EQ(127, max_gl);
- EXPECT_EQ(min_gl, SkColorGetA(result.getColor(299, 199)));
- EXPECT_EQ(max_gl, SkColorGetA(result.getColor(150, 0)));
- EXPECT_EQ(100U, SkColorGetA(result.getColor(0, 0)));
-
- EXPECT_TRUE(ApplyColorReduction(source, transform, true, &result));
- Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
- EXPECT_EQ(0, min_gl);
- EXPECT_EQ(255, max_gl);
- EXPECT_EQ(min_gl, SkColorGetA(result.getColor(299, 199)));
- EXPECT_EQ(max_gl, SkColorGetA(result.getColor(150, 0)));
- EXPECT_EQ(193U, SkColorGetA(result.getColor(0, 0)));
-}
-
TEST_F(ColorAnalysisTest, ComputeProminentColors) {
LumaRange lumas[] = {LumaRange::DARK, LumaRange::NORMAL, LumaRange::LIGHT};
SaturationRange saturations[] = {SaturationRange::VIBRANT,
diff --git a/ui/gfx/color_conversion_sk_filter_cache.cc b/ui/gfx/color_conversion_sk_filter_cache.cc
new file mode 100644
index 0000000..f6c3009
--- /dev/null
+++ b/ui/gfx/color_conversion_sk_filter_cache.cc
@@ -0,0 +1,245 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/color_conversion_sk_filter_cache.h"
+
+#include <string>
+
+#include "base/feature_list.h"
+#include "base/logging.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColorFilter.h"
+#include "third_party/skia/include/core/SkColorSpace.h"
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/gpu/GpuTypes.h"
+#include "third_party/skia/include/gpu/GrDirectContext.h"
+#include "third_party/skia/include/private/SkGainmapInfo.h"
+#include "third_party/skia/include/private/SkGainmapShader.h"
+#include "ui/gfx/color_transform.h"
+
+namespace gfx {
+
+namespace {
+
+// Allocate an SkSurface to be used to create the tonemapped result.
+static sk_sp<SkSurface> MakeSurfaceForResult(SkImageInfo image_info,
+ GrDirectContext* context) {
+ sk_sp<SkSurface> surface;
+ if (context) {
+ // TODO(https://crbug.com/1286088): Consider adding mipmap support here.
+ surface =
+ SkSurface::MakeRenderTarget(context, skgpu::Budgeted::kNo, image_info,
+ /*sampleCount=*/0, kTopLeft_GrSurfaceOrigin,
+ /*surfaceProps=*/nullptr,
+ /*shouldCreateWithMips=*/false);
+ // It is not guaranteed that kRGBA_F16_SkColorType is renderable. If we fail
+ // to create an SkSurface with that color type, fall back to
+ // kN32_SkColorType.
+ if (!surface) {
+ DLOG(ERROR) << "Falling back to tone mapped 8-bit surface.";
+ image_info = image_info.makeColorType(kN32_SkColorType);
+ surface = SkSurface::MakeRenderTarget(
+ context, skgpu::Budgeted::kNo, image_info,
+ /*sampleCount=*/0, kTopLeft_GrSurfaceOrigin,
+ /*surfaceProps=*/nullptr,
+ /*shouldCreateWithMips=*/false);
+ }
+ } else {
+ surface = SkSurface::MakeRaster(image_info, image_info.minRowBytes(),
+ /*surfaceProps=*/nullptr);
+ }
+ return surface;
+}
+
+} // namespace
+
+ColorConversionSkFilterCache::ColorConversionSkFilterCache() = default;
+ColorConversionSkFilterCache::~ColorConversionSkFilterCache() = default;
+
+bool ColorConversionSkFilterCache::Key::Key::operator==(
+ const Key& other) const {
+ return src == other.src && src_bit_depth == other.src_bit_depth &&
+ dst == other.dst &&
+ sdr_max_luminance_nits == other.sdr_max_luminance_nits;
+}
+
+bool ColorConversionSkFilterCache::Key::operator!=(const Key& other) const {
+ return !(*this == other);
+}
+
+bool ColorConversionSkFilterCache::Key::operator<(const Key& other) const {
+ return std::tie(src, src_bit_depth, dst, sdr_max_luminance_nits) <
+ std::tie(other.src, other.src_bit_depth, other.dst,
+ other.sdr_max_luminance_nits);
+}
+
+ColorConversionSkFilterCache::Key::Key(const gfx::ColorSpace& src,
+ uint32_t src_bit_depth,
+ const gfx::ColorSpace& dst,
+ float sdr_max_luminance_nits)
+ : src(src),
+ src_bit_depth(src_bit_depth),
+ dst(dst),
+ sdr_max_luminance_nits(sdr_max_luminance_nits) {}
+
+sk_sp<SkColorFilter> ColorConversionSkFilterCache::Get(
+ const gfx::ColorSpace& src,
+ const gfx::ColorSpace& dst,
+ float resource_offset,
+ float resource_multiplier,
+ absl::optional<uint32_t> src_bit_depth,
+ absl::optional<gfx::HDRMetadata> src_hdr_metadata,
+ float sdr_max_luminance_nits,
+ float dst_max_luminance_relative) {
+ // Set unused parameters to bogus values, so that they do not result in
+ // different keys for the same conversion.
+ if (!src.IsToneMappedByDefault()) {
+ // If the source is not going to be tone mapped, then `src_hdr_metadata`
+ // and `dst_max_luminance_relative` will not be used, so set them nonsense
+ // values.
+ src_hdr_metadata = absl::nullopt;
+ dst_max_luminance_relative = 0;
+
+ // If neither source nor destination will use `sdr_max_luminance_nits`, then
+ // set it to a nonsense value.
+ if (!dst.IsAffectedBySDRWhiteLevel() && !src.IsAffectedBySDRWhiteLevel()) {
+ sdr_max_luminance_nits = 0;
+ }
+ }
+
+ const Key key(src, src_bit_depth.value_or(0), dst, sdr_max_luminance_nits);
+ sk_sp<SkRuntimeEffect>& effect = cache_[key];
+
+ gfx::ColorTransform::Options options;
+ options.tone_map_pq_and_hlg_to_dst = true;
+ if (src_bit_depth)
+ options.src_bit_depth = src_bit_depth.value();
+ options.sdr_max_luminance_nits = sdr_max_luminance_nits;
+ options.src_hdr_metadata = src_hdr_metadata;
+ options.dst_max_luminance_relative = dst_max_luminance_relative;
+ if (!effect) {
+ std::unique_ptr<gfx::ColorTransform> transform =
+ gfx::ColorTransform::NewColorTransform(src, dst, options);
+ effect = transform->GetSkRuntimeEffect();
+ }
+
+ return effect->makeColorFilter(gfx::ColorTransform::GetSkShaderUniforms(
+ src, dst, resource_offset, resource_multiplier, options));
+}
+
+sk_sp<SkImage> ColorConversionSkFilterCache::ApplyGainmap(
+ sk_sp<SkImage> base_image,
+ sk_sp<SkImage> gainmap_image,
+ const SkGainmapInfo& gainmap_info,
+ float dst_max_luminance_relative,
+ GrDirectContext* context) {
+ DCHECK_EQ(base_image->isTextureBacked(), gainmap_image->isTextureBacked());
+ DCHECK_EQ(!!context, base_image->isTextureBacked());
+
+ // If `gainmap_image` will not be applied, then return `base_image` directly.
+ switch (gainmap_info.fBaseImageType) {
+ case SkGainmapInfo::BaseImageType::kSDR:
+ if (dst_max_luminance_relative <= gainmap_info.fDisplayRatioSdr) {
+ return base_image;
+ }
+ break;
+ case SkGainmapInfo::BaseImageType::kHDR:
+ if (dst_max_luminance_relative >= gainmap_info.fDisplayRatioHdr) {
+ return base_image;
+ }
+ break;
+ }
+
+ // The output surface will be in a linearized version of the input
+ // base_image's color space.
+ sk_sp<SkColorSpace> surface_color_space = base_image->refColorSpace();
+ if (surface_color_space) {
+ surface_color_space = surface_color_space->makeLinearGamma();
+ } else {
+ surface_color_space = SkColorSpace::MakeSRGBLinear();
+ }
+ SkImageInfo surface_info =
+ SkImageInfo::Make(base_image->dimensions(),
+ SkColorInfo(kRGBA_F16_SkColorType, kPremul_SkAlphaType,
+ surface_color_space));
+
+ // Create the surface to render the gainmap shader to.
+ sk_sp<SkSurface> surface = MakeSurfaceForResult(surface_info, context);
+ if (!surface) {
+ LOG(ERROR) << "Failed to create SkSurface for applying gainmap.";
+ return base_image;
+ }
+
+ // Render the gainmap shader to the surface
+ SkRect image_rect = SkRect::MakeSize(SkSize::Make(base_image->dimensions()));
+ SkRect gainmap_rect =
+ SkRect::MakeSize(SkSize::Make(gainmap_image->dimensions()));
+ SkRect surface_rect =
+ SkRect::MakeSize(SkSize::Make(surface_info.dimensions()));
+ sk_sp<SkShader> shader = SkGainmapShader::Make(
+ base_image, image_rect, SkSamplingOptions(), gainmap_image, gainmap_rect,
+ SkSamplingOptions(), gainmap_info, surface_rect,
+ dst_max_luminance_relative, surface_color_space);
+ DCHECK(shader);
+ SkPaint paint;
+ paint.setShader(shader);
+ surface->getCanvas()->drawRect(surface_rect, paint);
+
+ // Return the surface's contents as an SkImage.
+ return surface->makeImageSnapshot();
+}
+
+sk_sp<SkImage> ColorConversionSkFilterCache::ConvertImage(
+ sk_sp<SkImage> image,
+ sk_sp<SkColorSpace> target_color_space,
+ absl::optional<gfx::HDRMetadata> src_hdr_metadata,
+ float sdr_max_luminance_nits,
+ float dst_max_luminance_relative,
+ bool enable_tone_mapping,
+ GrDirectContext* context) {
+ DCHECK(image);
+ DCHECK(target_color_space);
+ sk_sp<SkColorSpace> image_sk_color_space = image->refColorSpace();
+ if (!image_sk_color_space)
+ return image->makeColorSpace(target_color_space, context);
+
+ if (!enable_tone_mapping)
+ return image->makeColorSpace(target_color_space, context);
+
+ gfx::ColorSpace image_color_space(*image_sk_color_space);
+ switch (image_color_space.GetTransferID()) {
+ case ColorSpace::TransferID::PQ:
+ case ColorSpace::TransferID::HLG:
+ break;
+ default:
+ return image->makeColorSpace(target_color_space, context);
+ }
+
+ SkImageInfo image_info =
+ SkImageInfo::Make(image->dimensions(),
+ SkColorInfo(kRGBA_F16_SkColorType, kPremul_SkAlphaType,
+ image_sk_color_space));
+ sk_sp<SkSurface> surface = MakeSurfaceForResult(image_info, context);
+ if (!surface) {
+ DLOG(ERROR) << "Failed to create SkSurface color conversion.";
+ return nullptr;
+ }
+
+ sk_sp<SkColorFilter> filter =
+ Get(image_color_space, gfx::ColorSpace(*target_color_space),
+ /*resource_offset=*/0, /*resource_multiplier=*/1,
+ /*src_bit_depth=*/absl::nullopt, src_hdr_metadata,
+ sdr_max_luminance_nits, dst_max_luminance_relative);
+ SkPaint paint;
+ paint.setBlendMode(SkBlendMode::kSrc);
+ paint.setColorFilter(filter);
+ SkSamplingOptions sampling_options(SkFilterMode::kNearest);
+ surface->getCanvas()->drawImage(image,
+ /*x=*/0, /*y=*/0, sampling_options, &paint);
+ return surface->makeImageSnapshot()->reinterpretColorSpace(
+ target_color_space);
+}
+
+} // namespace gfx
diff --git a/ui/gfx/color_conversion_sk_filter_cache.h b/ui/gfx/color_conversion_sk_filter_cache.h
new file mode 100644
index 0000000..9f5184d
--- /dev/null
+++ b/ui/gfx/color_conversion_sk_filter_cache.h
@@ -0,0 +1,99 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_COLOR_CONVERSION_SK_FILTER_CACHE_H_
+#define UI_GFX_COLOR_CONVERSION_SK_FILTER_CACHE_H_
+
+#include "base/containers/flat_map.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/color_space_export.h"
+#include "ui/gfx/gfx_export.h"
+#include "ui/gfx/hdr_metadata.h"
+
+class GrDirectContext;
+class SkImage;
+class SkColorFilter;
+class SkRuntimeEffect;
+struct SkGainmapInfo;
+
+namespace gfx {
+
+class COLOR_SPACE_EXPORT ColorConversionSkFilterCache {
+ public:
+ ColorConversionSkFilterCache();
+ ColorConversionSkFilterCache(const ColorConversionSkFilterCache&) = delete;
+ ColorConversionSkFilterCache& operator=(const ColorConversionSkFilterCache&) =
+ delete;
+ ~ColorConversionSkFilterCache();
+
+ // Retrieve an SkColorFilter to transform `src` to `dst`. The bit depth of
+ // `src` maybe specified in `src_bit_depth` (relevant only for YUV to RGB
+ // conversion). The filter also applies the offset `src_resource_offset` and
+ // then scales by `src_resource_multiplier`. Apply tone mapping of `src` is
+ // HLG or PQ, using `sdr_max_luminance_nits`, `src_hdr_metadata`, and
+ // `dst_max_luminance_relative` as parameters.
+ sk_sp<SkColorFilter> Get(const gfx::ColorSpace& src,
+ const gfx::ColorSpace& dst,
+ float resource_offset,
+ float resource_multiplier,
+ absl::optional<uint32_t> src_bit_depth,
+ absl::optional<gfx::HDRMetadata> src_hdr_metadata,
+ float sdr_max_luminance_nits,
+ float dst_max_luminance_relative);
+
+ // Convert `image` to be in `target_color_space`, performing tone mapping as
+ // needed (using `sdr_max_luminance_nits` and `dst_max_luminance_relative`).
+ // If `image` is GPU backed then `context` should be its GrDirectContext,
+ // otherwise, `context` should be nullptr. The resulting image will not have
+ // mipmaps.
+ // If the feature ImageToneMapping is disabled, then this function is
+ // equivalent to calling `image->makeColorSpace(target_color_space, context)`,
+ // and no tone mapping is performed.
+ sk_sp<SkImage> ConvertImage(sk_sp<SkImage> image,
+ sk_sp<SkColorSpace> target_color_space,
+ absl::optional<gfx::HDRMetadata> src_hdr_metadata,
+ float sdr_max_luminance_nits,
+ float dst_max_luminance_relative,
+ bool enable_tone_mapping,
+ GrDirectContext* context);
+
+ // Apply the gainmap in `gainmap_image` to `base_image`, using the parameters
+ // in `gainmap_info` and `dst_max_luminance_relative`, and return the
+ // resulting image.
+ // * If `context` is non-nullptr, then `base_image` and `gainmap_image` must
+ // be texture-backed and on `context`, and the result will be texture backed
+ // and on `context`.
+ // * If `context` is nullptr, then the arguments should be bitmaps, and the
+ // result will be a bitmap.
+ sk_sp<SkImage> ApplyGainmap(sk_sp<SkImage> base_image,
+ sk_sp<SkImage> gainmap_image,
+ const SkGainmapInfo& gainmap_info,
+ float dst_max_luminance_relative,
+ GrDirectContext* context);
+
+ public:
+ struct Key {
+ Key(const gfx::ColorSpace& src,
+ uint32_t src_bit_depth,
+ const gfx::ColorSpace& dst,
+ float sdr_max_luminance_nits);
+
+ gfx::ColorSpace src;
+ uint32_t src_bit_depth = 0;
+ gfx::ColorSpace dst;
+ float sdr_max_luminance_nits = 0.f;
+
+ bool operator==(const Key& other) const;
+ bool operator!=(const Key& other) const;
+ bool operator<(const Key& other) const;
+ };
+
+ base::flat_map<Key, sk_sp<SkRuntimeEffect>> cache_;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_COLOR_CONVERSION_SK_FILTER_CACHE_H_
diff --git a/ui/gfx/color_conversions.cc b/ui/gfx/color_conversions.cc
new file mode 100644
index 0000000..52d0761
--- /dev/null
+++ b/ui/gfx/color_conversions.cc
@@ -0,0 +1,572 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/color_conversions.h"
+
+#include <cmath>
+
+#include "skia/ext/skcolorspace_primaries.h"
+#include "skia/ext/skcolorspace_trfn.h"
+#include "third_party/skia/include/core/SkColorSpace.h"
+#include "third_party/skia/modules/skcms/skcms.h"
+#include "ui/gfx/color_space.h"
+#include "ui/gfx/geometry/angle_conversions.h"
+
+namespace gfx {
+
+// Namespace containing some of the helper methods for color conversions.
+namespace {
+// https://en.wikipedia.org/wiki/CIELAB_color_space#Converting_between_CIELAB_and_CIEXYZ_coordinates
+constexpr float kD50_x = 0.9642f;
+constexpr float kD50_y = 1.0f;
+constexpr float kD50_z = 0.8251f;
+
+const skcms_Matrix3x3* getXYDZ65toXYZD50matrix() {
+ constexpr float kD65_x = 0.3127f;
+ constexpr float kD65_y = 0.3290f;
+ static skcms_Matrix3x3 adapt_d65_to_d50;
+ skcms_AdaptToXYZD50(kD65_x, kD65_y, &adapt_d65_to_d50);
+ return &adapt_d65_to_d50;
+}
+
+const skcms_Matrix3x3* getXYDZ50toXYZD65matrix() {
+ static skcms_Matrix3x3 adapt_d50_to_d65;
+ skcms_Matrix3x3_invert(getXYDZ65toXYZD50matrix(), &adapt_d50_to_d65);
+ return &adapt_d50_to_d65;
+}
+
+const skcms_Matrix3x3* getXYZD50TosRGBLinearMatrix() {
+ static skcms_Matrix3x3 xyzd50_to_srgb_linear;
+ skcms_Matrix3x3_invert(&SkNamedGamut::kSRGB, &xyzd50_to_srgb_linear);
+ return &xyzd50_to_srgb_linear;
+}
+
+const skcms_Matrix3x3* getkXYZD65tosRGBMatrix() {
+ static skcms_Matrix3x3 adapt_XYZD65_to_srgb = skcms_Matrix3x3_concat(
+ getXYZD50TosRGBLinearMatrix(), getXYDZ65toXYZD50matrix());
+ return &adapt_XYZD65_to_srgb;
+}
+
+const skcms_Matrix3x3* getProPhotoRGBtoXYZD50Matrix() {
+ static skcms_Matrix3x3 lin_proPhoto_to_XYZ_D50;
+ SkNamedPrimariesExt::kProPhotoRGB.toXYZD50(&lin_proPhoto_to_XYZ_D50);
+ return &lin_proPhoto_to_XYZ_D50;
+}
+
+const skcms_Matrix3x3* getXYZD50toProPhotoRGBMatrix() {
+ static skcms_Matrix3x3 xyzd50_to_ProPhotoRGB;
+ skcms_Matrix3x3_invert(getProPhotoRGBtoXYZD50Matrix(),
+ &xyzd50_to_ProPhotoRGB);
+ return &xyzd50_to_ProPhotoRGB;
+}
+
+const skcms_Matrix3x3* getXYZD50toDisplayP3Matrix() {
+ static skcms_Matrix3x3 xyzd50_to_DisplayP3;
+ skcms_Matrix3x3_invert(&SkNamedGamut::kDisplayP3, &xyzd50_to_DisplayP3);
+ return &xyzd50_to_DisplayP3;
+}
+
+const skcms_Matrix3x3* getXYZD50toAdobeRGBMatrix() {
+ static skcms_Matrix3x3 xyzd50_to_kAdobeRGB;
+ skcms_Matrix3x3_invert(&SkNamedGamut::kAdobeRGB, &xyzd50_to_kAdobeRGB);
+ return &xyzd50_to_kAdobeRGB;
+}
+
+const skcms_Matrix3x3* getXYZD50toRec2020Matrix() {
+ static skcms_Matrix3x3 xyzd50_to_Rec2020;
+ skcms_Matrix3x3_invert(&SkNamedGamut::kRec2020, &xyzd50_to_Rec2020);
+ return &xyzd50_to_Rec2020;
+}
+
+const skcms_Matrix3x3* getXYZToLMSMatrix() {
+ static const skcms_Matrix3x3 kXYZ_to_LMS = {
+ {{0.8190224432164319f, 0.3619062562801221f, -0.12887378261216414f},
+ {0.0329836671980271f, 0.9292868468965546f, 0.03614466816999844f},
+ {0.048177199566046255f, 0.26423952494422764f, 0.6335478258136937f}}};
+ return &kXYZ_to_LMS;
+}
+
+const skcms_Matrix3x3* getLMSToXYZMatrix() {
+ static skcms_Matrix3x3 LMS_to_XYZ;
+ skcms_Matrix3x3_invert(getXYZToLMSMatrix(), &LMS_to_XYZ);
+ return &LMS_to_XYZ;
+}
+
+const skcms_Matrix3x3* getOklabToLMSMatrix() {
+ static const skcms_Matrix3x3 kOklab_to_LMS = {
+ {{0.99999999845051981432f, 0.39633779217376785678f,
+ 0.21580375806075880339f},
+ {1.0000000088817607767f, -0.1055613423236563494f,
+ -0.063854174771705903402f},
+ {1.0000000546724109177f, -0.089484182094965759684f,
+ -1.2914855378640917399f}}};
+ return &kOklab_to_LMS;
+}
+
+const skcms_Matrix3x3* getLMSToOklabMatrix() {
+ static skcms_Matrix3x3 LMS_to_Oklab;
+ skcms_Matrix3x3_invert(getOklabToLMSMatrix(), &LMS_to_Oklab);
+ return &LMS_to_Oklab;
+}
+
+typedef struct {
+ float vals[3];
+} skcms_Vector3;
+
+static skcms_Vector3 skcms_Matrix3x3_apply(const skcms_Matrix3x3* m,
+ const skcms_Vector3* v) {
+ skcms_Vector3 dst = {{0, 0, 0}};
+ for (int row = 0; row < 3; ++row) {
+ dst.vals[row] = m->vals[row][0] * v->vals[0] +
+ m->vals[row][1] * v->vals[1] + m->vals[row][2] * v->vals[2];
+ }
+ return dst;
+}
+
+skcms_TransferFunction* getSRGBInverseTransferFunction() {
+ static skcms_TransferFunction srgb_inverse;
+ skcms_TransferFunction_invert(&SkNamedTransferFn::kSRGB, &srgb_inverse);
+ return &srgb_inverse;
+}
+
+std::tuple<float, float, float> ApplyInverseTransferFnsRGB(float r,
+ float g,
+ float b) {
+ return std::make_tuple(
+ skcms_TransferFunction_eval(getSRGBInverseTransferFunction(), r),
+ skcms_TransferFunction_eval(getSRGBInverseTransferFunction(), g),
+ skcms_TransferFunction_eval(getSRGBInverseTransferFunction(), b));
+}
+
+std::tuple<float, float, float> ApplyTransferFnsRGB(float r, float g, float b) {
+ return std::make_tuple(
+ skcms_TransferFunction_eval(&SkNamedTransferFn::kSRGB, r),
+ skcms_TransferFunction_eval(&SkNamedTransferFn::kSRGB, g),
+ skcms_TransferFunction_eval(&SkNamedTransferFn::kSRGB, b));
+}
+
+std::tuple<float, float, float> ApplyTransferFnProPhoto(float r,
+ float g,
+ float b) {
+ return std::make_tuple(
+ skcms_TransferFunction_eval(&SkNamedTransferFnExt::kProPhotoRGB, r),
+ skcms_TransferFunction_eval(&SkNamedTransferFnExt::kProPhotoRGB, g),
+ skcms_TransferFunction_eval(&SkNamedTransferFnExt::kProPhotoRGB, b));
+}
+
+std::tuple<float, float, float> ApplyTransferFnAdobeRGB(float r,
+ float g,
+ float b) {
+ return std::make_tuple(
+ skcms_TransferFunction_eval(&SkNamedTransferFn::k2Dot2, r),
+ skcms_TransferFunction_eval(&SkNamedTransferFn::k2Dot2, g),
+ skcms_TransferFunction_eval(&SkNamedTransferFn::k2Dot2, b));
+}
+
+skcms_TransferFunction* getProPhotoInverseTransferFunction() {
+ static skcms_TransferFunction ProPhoto_inverse;
+ skcms_TransferFunction_invert(&SkNamedTransferFnExt::kProPhotoRGB,
+ &ProPhoto_inverse);
+ return &ProPhoto_inverse;
+}
+
+std::tuple<float, float, float> ApplyInverseTransferFnProPhoto(float r,
+ float g,
+ float b) {
+ return std::make_tuple(
+ skcms_TransferFunction_eval(getProPhotoInverseTransferFunction(), r),
+ skcms_TransferFunction_eval(getProPhotoInverseTransferFunction(), g),
+ skcms_TransferFunction_eval(getProPhotoInverseTransferFunction(), b));
+}
+
+skcms_TransferFunction* getAdobeRGBInverseTransferFunction() {
+ static skcms_TransferFunction AdobeRGB_inverse;
+ skcms_TransferFunction_invert(&SkNamedTransferFn::k2Dot2, &AdobeRGB_inverse);
+ return &AdobeRGB_inverse;
+}
+
+std::tuple<float, float, float> ApplyInverseTransferFnAdobeRGB(float r,
+ float g,
+ float b) {
+ return std::make_tuple(
+ skcms_TransferFunction_eval(getAdobeRGBInverseTransferFunction(), r),
+ skcms_TransferFunction_eval(getAdobeRGBInverseTransferFunction(), g),
+ skcms_TransferFunction_eval(getAdobeRGBInverseTransferFunction(), b));
+}
+
+std::tuple<float, float, float> ApplyTransferFnRec2020(float r,
+ float g,
+ float b) {
+ return std::make_tuple(
+ skcms_TransferFunction_eval(&SkNamedTransferFn::kRec2020, r),
+ skcms_TransferFunction_eval(&SkNamedTransferFn::kRec2020, g),
+ skcms_TransferFunction_eval(&SkNamedTransferFn::kRec2020, b));
+}
+
+skcms_TransferFunction* getRec2020nverseTransferFunction() {
+ static skcms_TransferFunction Rec2020_inverse;
+ skcms_TransferFunction_invert(&SkNamedTransferFn::kRec2020, &Rec2020_inverse);
+ return &Rec2020_inverse;
+}
+
+std::tuple<float, float, float> ApplyInverseTransferFnRec2020(float r,
+ float g,
+ float b) {
+ return std::make_tuple(
+ skcms_TransferFunction_eval(getRec2020nverseTransferFunction(), r),
+ skcms_TransferFunction_eval(getRec2020nverseTransferFunction(), g),
+ skcms_TransferFunction_eval(getRec2020nverseTransferFunction(), b));
+}
+} // namespace
+
+std::tuple<float, float, float> LabToXYZD50(float l, float a, float b) {
+ float y = (l + 16.0f) / 116.0f;
+ float x = y + a / 500.0f;
+ float z = y - b / 200.0f;
+
+ auto LabInverseTransferFunction = [](float t) {
+ constexpr float delta = (24.0f / 116.0f);
+
+ if (t <= delta) {
+ return (108.0f / 841.0f) * (t - (16.0f / 116.0f));
+ }
+
+ return t * t * t;
+ };
+
+ x = LabInverseTransferFunction(x) * kD50_x;
+ y = LabInverseTransferFunction(y) * kD50_y;
+ z = LabInverseTransferFunction(z) * kD50_z;
+
+ return std::make_tuple(x, y, z);
+}
+
+std::tuple<float, float, float> XYZD50ToLab(float x, float y, float z) {
+ auto LabTransferFunction = [](float t) {
+ constexpr float delta_limit =
+ (24.0f / 116.0f) * (24.0f / 116.0f) * (24.0f / 116.0f);
+
+ if (t <= delta_limit)
+ return (841.0f / 108.0f) * t + (16.0f / 116.0f);
+ else
+ return std::pow(t, 1.0f / 3.0f);
+ };
+
+ x = LabTransferFunction(x / kD50_x);
+ y = LabTransferFunction(y / kD50_y);
+ z = LabTransferFunction(z / kD50_z);
+
+ float l = 116.0f * y - 16.0f;
+ float a = 500.0f * (x - y);
+ float b = 200.0f * (y - z);
+
+ return std::make_tuple(l, a, b);
+}
+
+std::tuple<float, float, float> OklabToXYZD65(float l, float a, float b) {
+ skcms_Vector3 lab_input{{l / 100.f, a, b}};
+ skcms_Vector3 lms_intermediate =
+ skcms_Matrix3x3_apply(getOklabToLMSMatrix(), &lab_input);
+ lms_intermediate.vals[0] = lms_intermediate.vals[0] *
+ lms_intermediate.vals[0] *
+ lms_intermediate.vals[0];
+ lms_intermediate.vals[1] = lms_intermediate.vals[1] *
+ lms_intermediate.vals[1] *
+ lms_intermediate.vals[1];
+ lms_intermediate.vals[2] = lms_intermediate.vals[2] *
+ lms_intermediate.vals[2] *
+ lms_intermediate.vals[2];
+ skcms_Vector3 xyz_output =
+ skcms_Matrix3x3_apply(getLMSToXYZMatrix(), &lms_intermediate);
+ return std::make_tuple(xyz_output.vals[0], xyz_output.vals[1],
+ xyz_output.vals[2]);
+}
+
+std::tuple<float, float, float> XYZD65ToOklab(float x, float y, float z) {
+ skcms_Vector3 xyz_input{{x, y, z}};
+ skcms_Vector3 lms_intermediate =
+ skcms_Matrix3x3_apply(getXYZToLMSMatrix(), &xyz_input);
+
+ lms_intermediate.vals[0] = pow(lms_intermediate.vals[0], 1.0f / 3.0f);
+ lms_intermediate.vals[1] = pow(lms_intermediate.vals[1], 1.0f / 3.0f);
+ lms_intermediate.vals[2] = pow(lms_intermediate.vals[2], 1.0f / 3.0f);
+
+ skcms_Vector3 lab_output =
+ skcms_Matrix3x3_apply(getLMSToOklabMatrix(), &lms_intermediate);
+ return std::make_tuple(lab_output.vals[0] * 100.0f, lab_output.vals[1],
+ lab_output.vals[2]);
+}
+
+std::tuple<float, float, float> LchToLab(float l,
+ float c,
+ absl::optional<float> h) {
+ if (!h.has_value())
+ return std::make_tuple(l, 0, 0);
+
+ return std::make_tuple(l, c * std::cos(gfx::DegToRad(h.value())),
+ c * std::sin(gfx::DegToRad(h.value())));
+}
+std::tuple<float, float, float> LabToLch(float l, float a, float b) {
+ return std::make_tuple(l, std::sqrt(a * a + b * b),
+ gfx::RadToDeg(atan2f(b, a)));
+}
+
+std::tuple<float, float, float> DisplayP3ToXYZD50(float r, float g, float b) {
+ auto [r_, g_, b_] = ApplyTransferFnsRGB(r, g, b);
+ skcms_Vector3 rgb_input{{r_, g_, b_}};
+ skcms_Vector3 xyz_output =
+ skcms_Matrix3x3_apply(&SkNamedGamut::kDisplayP3, &rgb_input);
+ return std::make_tuple(xyz_output.vals[0], xyz_output.vals[1],
+ xyz_output.vals[2]);
+}
+
+std::tuple<float, float, float> XYZD50ToDisplayP3(float x, float y, float z) {
+ skcms_Vector3 xyz_input{{x, y, z}};
+ skcms_Vector3 rgb_output =
+ skcms_Matrix3x3_apply(getXYZD50toDisplayP3Matrix(), &xyz_input);
+ return ApplyInverseTransferFnsRGB(rgb_output.vals[0], rgb_output.vals[1],
+ rgb_output.vals[2]);
+}
+
+std::tuple<float, float, float> ProPhotoToXYZD50(float r, float g, float b) {
+ auto [r_, g_, b_] = ApplyTransferFnProPhoto(r, g, b);
+ skcms_Vector3 rgb_input{{r_, g_, b_}};
+ skcms_Vector3 xyz_output =
+ skcms_Matrix3x3_apply(getProPhotoRGBtoXYZD50Matrix(), &rgb_input);
+ return std::make_tuple(xyz_output.vals[0], xyz_output.vals[1],
+ xyz_output.vals[2]);
+}
+
+std::tuple<float, float, float> XYZD50ToProPhoto(float x, float y, float z) {
+ skcms_Vector3 xyz_input{{x, y, z}};
+ skcms_Vector3 rgb_output =
+ skcms_Matrix3x3_apply(getXYZD50toProPhotoRGBMatrix(), &xyz_input);
+ return ApplyInverseTransferFnProPhoto(rgb_output.vals[0], rgb_output.vals[1],
+ rgb_output.vals[2]);
+}
+
+std::tuple<float, float, float> AdobeRGBToXYZD50(float r, float g, float b) {
+ auto [r_, g_, b_] = ApplyTransferFnAdobeRGB(r, g, b);
+ skcms_Vector3 rgb_input{{r_, g_, b_}};
+ skcms_Vector3 xyz_output =
+ skcms_Matrix3x3_apply(&SkNamedGamut::kAdobeRGB, &rgb_input);
+ return std::make_tuple(xyz_output.vals[0], xyz_output.vals[1],
+ xyz_output.vals[2]);
+}
+
+std::tuple<float, float, float> XYZD50ToAdobeRGB(float x, float y, float z) {
+ skcms_Vector3 xyz_input{{x, y, z}};
+ skcms_Vector3 rgb_output =
+ skcms_Matrix3x3_apply(getXYZD50toAdobeRGBMatrix(), &xyz_input);
+ return ApplyInverseTransferFnAdobeRGB(rgb_output.vals[0], rgb_output.vals[1],
+ rgb_output.vals[2]);
+}
+
+std::tuple<float, float, float> Rec2020ToXYZD50(float r, float g, float b) {
+ auto [r_, g_, b_] = ApplyTransferFnRec2020(r, g, b);
+ skcms_Vector3 rgb_input{{r_, g_, b_}};
+ skcms_Vector3 xyz_output =
+ skcms_Matrix3x3_apply(&SkNamedGamut::kRec2020, &rgb_input);
+ return std::make_tuple(xyz_output.vals[0], xyz_output.vals[1],
+ xyz_output.vals[2]);
+}
+
+std::tuple<float, float, float> XYZD50ToRec2020(float x, float y, float z) {
+ skcms_Vector3 xyz_input{{x, y, z}};
+ skcms_Vector3 rgb_output =
+ skcms_Matrix3x3_apply(getXYZD50toRec2020Matrix(), &xyz_input);
+ return ApplyInverseTransferFnRec2020(rgb_output.vals[0], rgb_output.vals[1],
+ rgb_output.vals[2]);
+}
+
+std::tuple<float, float, float> XYZD50ToD65(float x, float y, float z) {
+ skcms_Vector3 xyz_input{{x, y, z}};
+ skcms_Vector3 xyz_output =
+ skcms_Matrix3x3_apply(getXYDZ50toXYZD65matrix(), &xyz_input);
+ return std::make_tuple(xyz_output.vals[0], xyz_output.vals[1],
+ xyz_output.vals[2]);
+}
+
+std::tuple<float, float, float> XYZD65ToD50(float x, float y, float z) {
+ skcms_Vector3 xyz_input{{x, y, z}};
+ skcms_Vector3 xyz_output =
+ skcms_Matrix3x3_apply(getXYDZ65toXYZD50matrix(), &xyz_input);
+ return std::make_tuple(xyz_output.vals[0], xyz_output.vals[1],
+ xyz_output.vals[2]);
+}
+
+std::tuple<float, float, float> XYZD65TosRGBLinear(float x, float y, float z) {
+ skcms_Vector3 xyz_input{{x, y, z}};
+ skcms_Vector3 rgb_result =
+ skcms_Matrix3x3_apply(getkXYZD65tosRGBMatrix(), &xyz_input);
+ return std::make_tuple(rgb_result.vals[0], rgb_result.vals[1],
+ rgb_result.vals[2]);
+}
+
+std::tuple<float, float, float> XYZD50TosRGBLinear(float x, float y, float z) {
+ skcms_Vector3 xyz_input{{x, y, z}};
+ skcms_Vector3 rgb_result =
+ skcms_Matrix3x3_apply(getXYZD50TosRGBLinearMatrix(), &xyz_input);
+ return std::make_tuple(rgb_result.vals[0], rgb_result.vals[1],
+ rgb_result.vals[2]);
+}
+
+std::tuple<float, float, float> SRGBLinearToXYZD50(float r, float g, float b) {
+ skcms_Vector3 rgb_input{{r, g, b}};
+ skcms_Vector3 xyz_output =
+ skcms_Matrix3x3_apply(&SkNamedGamut::kSRGB, &rgb_input);
+ return std::make_tuple(xyz_output.vals[0], xyz_output.vals[1],
+ xyz_output.vals[2]);
+}
+
+std::tuple<float, float, float> SRGBToXYZD50(float r, float g, float b) {
+ auto [r_, g_, b_] = ApplyTransferFnsRGB(r, g, b);
+ skcms_Vector3 rgb_input{{r_, g_, b_}};
+ skcms_Vector3 xyz_output =
+ skcms_Matrix3x3_apply(&SkNamedGamut::kSRGB, &rgb_input);
+ return std::make_tuple(xyz_output.vals[0], xyz_output.vals[1],
+ xyz_output.vals[2]);
+}
+
+std::tuple<float, float, float> SRGBToHSL(float r, float g, float b) {
+ float max = std::max({r, g, b});
+ float min = std::min({r, g, b});
+ float hue = 0.0f, saturation = 0.0f, ligth = (max + min) / 2.0f;
+ float d = max - min;
+
+ if (d != 0.0f) {
+ saturation = (ligth == 0.0f || ligth == 1.0f)
+ ? 0.0f
+ : (max - ligth) / std::min(ligth, 1 - ligth);
+ if (max == r) {
+ hue = (g - b) / d + (g < b ? 6.0f : 0.0f);
+ } else if (max == g) {
+ hue = (b - r) / d + 2.0f;
+ } else { // if(max == b)
+ hue = (r - g) / d + 4.0f;
+ }
+ }
+
+ return std::make_tuple(hue, saturation, ligth);
+}
+
+std::tuple<float, float, float> SRGBToHWB(float r, float g, float b) {
+ auto [hue, saturation, light] = SRGBToHSL(r, g, b);
+ float white = std::min({r, g, b});
+ float black = 1.0f - std::max({r, g, b});
+
+ return std::make_tuple(hue, white, black);
+}
+
+SkColor4f SRGBLinearToSkColor4f(float r, float g, float b, float alpha) {
+ auto [srgb_r, srgb_g, srgb_b] = ApplyInverseTransferFnsRGB(r, g, b);
+ return SkColor4f{srgb_r, srgb_g, srgb_b, alpha};
+}
+
+SkColor4f XYZD50ToSkColor4f(float x, float y, float z, float alpha) {
+ auto [r, g, b] = XYZD50TosRGBLinear(x, y, z);
+ return SRGBLinearToSkColor4f(r, g, b, alpha);
+}
+
+SkColor4f XYZD65ToSkColor4f(float x, float y, float z, float alpha) {
+ auto [r, g, b] = XYZD65TosRGBLinear(x, y, z);
+ return SRGBLinearToSkColor4f(r, g, b, alpha);
+}
+
+SkColor4f LabToSkColor4f(float l, float a, float b, float alpha) {
+ auto [x, y, z] = LabToXYZD50(l, a, b);
+ return XYZD50ToSkColor4f(x, y, z, alpha);
+}
+
+SkColor4f ProPhotoToSkColor4f(float r, float g, float b, float alpha) {
+ auto [x, y, z] = ProPhotoToXYZD50(r, g, b);
+ return XYZD50ToSkColor4f(x, y, z, alpha);
+}
+
+SkColor4f OklabToSkColor4f(float l, float a, float b, float alpha) {
+ auto [x, y, z] = OklabToXYZD65(l, a, b);
+ return XYZD65ToSkColor4f(x, y, z, alpha);
+}
+
+SkColor4f DisplayP3ToSkColor4f(float r, float g, float b, float alpha) {
+ auto [x, y, z] = DisplayP3ToXYZD50(r, g, b);
+ return XYZD50ToSkColor4f(x, y, z, alpha);
+}
+
+SkColor4f LchToSkColor4f(float l_input,
+ float c,
+ absl::optional<float> h,
+ float alpha) {
+ auto [l, a, b] = LchToLab(l_input, c, h);
+ auto [x, y, z] = LabToXYZD50(l, a, b);
+ return XYZD50ToSkColor4f(x, y, z, alpha);
+}
+SkColor4f AdobeRGBToSkColor4f(float r, float g, float b, float alpha) {
+ auto [x, y, z] = AdobeRGBToXYZD50(r, g, b);
+ return XYZD50ToSkColor4f(x, y, z, alpha);
+}
+
+SkColor4f Rec2020ToSkColor4f(float r, float g, float b, float alpha) {
+ auto [x, y, z] = Rec2020ToXYZD50(r, g, b);
+ return XYZD50ToSkColor4f(x, y, z, alpha);
+}
+
+SkColor4f OklchToSkColor4f(float l_input,
+ float c,
+ absl::optional<float> h,
+ float alpha) {
+ auto [l, a, b] = LchToLab(l_input, c, h);
+ auto [x, y, z] = OklabToXYZD65(l, a, b);
+ return XYZD65ToSkColor4f(x, y, z, alpha);
+}
+
+SkColor4f HSLToSkColor4f(float h, float s, float l, float alpha) {
+ // Explanation of this algorithm can be found in the CSS Color 4 Module
+ // specification at https://drafts.csswg.org/css-color-4/#hsl-to-rgb with
+ // further explanation available at
+ // http://en.wikipedia.org/wiki/HSL_color_space
+
+ // Hue is in the range of 0.0 to 6.0, the remainder are in the range 0.0
+ // to 1.0. Out parameters r, g, and b are also returned in range 0.0 to 1.0.
+ if (!s) {
+ return SkColor4f{l, l, l, alpha};
+ }
+ float temp2 = l <= 0.5 ? l * (1.0 + s) : l + s - l * s;
+ float temp1 = 2.0 * l - temp2;
+
+ auto CalcHue = [](float temp1, float temp2, float hue_val) {
+ if (hue_val < 0.0f)
+ hue_val += 6.0f;
+ else if (hue_val >= 6.0f)
+ hue_val -= 6.0f;
+ if (hue_val < 1.0f)
+ return temp1 + (temp2 - temp1) * hue_val;
+ if (hue_val < 3.0f)
+ return temp2;
+ if (hue_val < 4.0f)
+ return temp1 + (temp2 - temp1) * (4.0f - hue_val);
+ return temp1;
+ };
+
+ return SkColor4f{CalcHue(temp1, temp2, h + 2.0), CalcHue(temp1, temp2, h),
+ CalcHue(temp1, temp2, h - 2.0), alpha};
+}
+
+SkColor4f HWBToSkColor4f(float h, float w, float b, float alpha) {
+ if (w + b >= 1.0f) {
+ float gray = (w / (w + b));
+ return SkColor4f{gray, gray, gray, alpha};
+ }
+
+ // Leverage HSL to RGB conversion to find HWB to RGB, see
+ // https://drafts.csswg.org/css-color-4/#hwb-to-rgb
+ SkColor4f result = HSLToSkColor4f(h, 1.0f, 0.5f, alpha);
+
+ result.fR += w - (w + b) * result.fR;
+ result.fG += w - (w + b) * result.fG;
+ result.fB += w - (w + b) * result.fB;
+
+ return result;
+}
+} // namespace gfx
diff --git a/ui/gfx/color_conversions.h b/ui/gfx/color_conversions.h
new file mode 100644
index 0000000..59aad88
--- /dev/null
+++ b/ui/gfx/color_conversions.h
@@ -0,0 +1,150 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_COLOR_CONVERSIONS_H_
+#define UI_GFX_COLOR_CONVERSIONS_H_
+
+#include <tuple>
+
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// All the methods below are exposed for blink::color conversions.
+
+GFX_EXPORT std::tuple<float, float, float> LabToXYZD50(float l,
+ float a,
+ float b);
+
+GFX_EXPORT std::tuple<float, float, float> XYZD50ToLab(float x,
+ float y,
+ float z);
+
+GFX_EXPORT std::tuple<float, float, float> OklabToXYZD65(float l,
+ float a,
+ float b);
+
+GFX_EXPORT std::tuple<float, float, float> XYZD65ToOklab(float x,
+ float y,
+ float z);
+
+GFX_EXPORT std::tuple<float, float, float> LchToLab(float l,
+ float c,
+ absl::optional<float> h);
+
+GFX_EXPORT std::tuple<float, float, float> LabToLch(float l, float a, float b);
+
+GFX_EXPORT std::tuple<float, float, float> DisplayP3ToXYZD50(float r,
+ float g,
+ float b);
+
+GFX_EXPORT std::tuple<float, float, float> XYZD50ToDisplayP3(float x,
+ float y,
+ float z);
+
+GFX_EXPORT std::tuple<float, float, float> ProPhotoToXYZD50(float r,
+ float g,
+ float b);
+
+GFX_EXPORT std::tuple<float, float, float> XYZD50ToProPhoto(float x,
+ float y,
+ float z);
+
+GFX_EXPORT std::tuple<float, float, float> AdobeRGBToXYZD50(float r,
+ float g,
+ float b);
+
+GFX_EXPORT std::tuple<float, float, float> XYZD50ToAdobeRGB(float x,
+ float y,
+ float z);
+
+GFX_EXPORT std::tuple<float, float, float> Rec2020ToXYZD50(float r,
+ float g,
+ float b);
+
+GFX_EXPORT std::tuple<float, float, float> XYZD50ToRec2020(float x,
+ float y,
+ float z);
+
+GFX_EXPORT std::tuple<float, float, float> XYZD50ToD65(float x,
+ float y,
+ float z);
+
+GFX_EXPORT std::tuple<float, float, float> XYZD65ToD50(float x,
+ float y,
+ float z);
+
+GFX_EXPORT std::tuple<float, float, float> XYZD65TosRGBLinear(float x,
+ float y,
+ float z);
+
+GFX_EXPORT std::tuple<float, float, float> XYZD50TosRGBLinear(float x,
+ float y,
+ float z);
+
+GFX_EXPORT std::tuple<float, float, float> SRGBLinearToXYZD50(float r,
+ float g,
+ float b);
+
+GFX_EXPORT std::tuple<float, float, float> SRGBToXYZD50(float r,
+ float g,
+ float b);
+
+GFX_EXPORT std::tuple<float, float, float> SRGBToHSL(float r, float g, float b);
+
+GFX_EXPORT std::tuple<float, float, float> SRGBToHWB(float r, float g, float b);
+
+GFX_EXPORT SkColor4f XYZD50ToSkColor4f(float x, float y, float z, float alpha);
+
+GFX_EXPORT SkColor4f XYZD65ToSkColor4f(float x, float y, float z, float alpha);
+
+GFX_EXPORT SkColor4f LabToSkColor4f(float l, float a, float b, float alpha);
+
+GFX_EXPORT SkColor4f OklabToSkColor4f(float l, float a, float b, float alpha);
+
+GFX_EXPORT SkColor4f LchToSkColor4f(float l,
+ float a,
+ absl::optional<float> b,
+ float alpha);
+
+GFX_EXPORT SkColor4f OklchToSkColor4f(float l,
+ float a,
+ absl::optional<float> b,
+ float alpha);
+
+GFX_EXPORT SkColor4f SRGBLinearToSkColor4f(float r,
+ float g,
+ float b,
+ float alpha);
+
+GFX_EXPORT SkColor4f ProPhotoToSkColor4f(float r,
+ float g,
+ float b,
+ float alpha);
+
+GFX_EXPORT SkColor4f DisplayP3ToSkColor4f(float r,
+ float g,
+ float b,
+ float alpha);
+
+GFX_EXPORT SkColor4f AdobeRGBToSkColor4f(float r,
+ float g,
+ float b,
+ float alpha);
+
+GFX_EXPORT SkColor4f Rec2020ToSkColor4f(float r, float g, float b, float alpha);
+
+// Hue is in the range of 0.0 to 6.0, the rest of the parameters are in the
+// range 0.0 to 1.0.
+GFX_EXPORT SkColor4f HSLToSkColor4f(float h, float s, float l, float alpha);
+
+// Hue is in the range of 0.0 to 6.0, the rest of the parameters are in the
+// range 0.0 to 1.0.
+GFX_EXPORT SkColor4f HWBToSkColor4f(float h, float w, float b, float alpha);
+
+} // namespace gfx
+
+#endif // UI_GFX_COLOR_CONVERSIONS_H_
\ No newline at end of file
diff --git a/ui/gfx/color_conversions_unittest.cc b/ui/gfx/color_conversions_unittest.cc
new file mode 100644
index 0000000..2f45a7e
--- /dev/null
+++ b/ui/gfx/color_conversions_unittest.cc
@@ -0,0 +1,1287 @@
+// Copyright 2006-2008 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stdlib.h>
+#include <tuple>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/color_conversions.h"
+
+namespace gfx {
+
+namespace {
+// Helper struct for testing purposes.
+struct ColorTest {
+ std::tuple<float, float, float> input;
+ std::tuple<float, float, float> expected;
+};
+} // namespace
+
+TEST(ColorConversions, LabToXYZD50) {
+ // Color conversions obtained from
+ // https://www.nixsensor.com/free-color-converter/
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{100.0f, 0.0f, 0.0f}, {0.9642f, 1.0f, 0.8252f}}, // white
+ {{33.0f, 0.0f, 0.0f}, {0.0727f, 0.0754f, 0.0622f}}, // gray1
+ {{66.0f, 0.0f, 0.0f}, {0.3406f, 0.3532f, 0.2915f}}, // gray2
+ {{20.0f, -35.0f, 45.0f}, {0.0134f, 0.0299f, -0.0056f}}, // dark_green
+ {{80.0f, -60.0f, 70.0f}, {0.3416f, 0.5668f, 0.0899f}}, // ligth_green
+ {{35.0f, 60.0f, 70.0f}, {0.1690f, 0.0850f, -0.0051f}}, // purple
+ {{75.0f, 45.0f, -100.0f}, {0.6448f, 0.4828f, 1.7488f}}, // lile
+ {{75.0f, 100.0f, 80.0f}, {0.92f, 0.4828f, 0.0469f}}}; // red
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_l, input_a, input_b] = color_pair.input;
+ auto [expected_x, expected_y, expected_z] = color_pair.expected;
+ auto [output_x, output_y, output_z] =
+ LabToXYZD50(input_l, input_a, input_b);
+ EXPECT_NEAR(output_x, expected_x, 0.001f)
+ << input_l << ' ' << input_a << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_y, expected_y, 0.001f)
+ << input_l << ' ' << input_a << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_z, expected_z, 0.001f)
+ << input_l << ' ' << input_a << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ }
+}
+
+TEST(ColorConversions, XYZD50ToLab) {
+ // Color conversions obtained from
+ // https://www.nixsensor.com/free-color-converter/
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.9642f, 1.0f, 0.8252f}, {100.0f, 0.0f, 0.0f}}, // white
+ {{0.0727f, 0.0754f, 0.0622f}, {33.0f, 0.0f, 0.0f}}, // gray1
+ {{0.3406f, 0.3532f, 0.2915f}, {66.0f, 0.0f, 0.0f}}, // gray2
+ {{0.0134f, 0.0299f, -0.0056f}, {20.0f, -35.0f, 45.0f}}, // dark_green
+ {{0.3416f, 0.5668f, 0.0899f}, {80.0f, -60.0f, 70.0f}}, // ligth_green
+ {{0.1690f, 0.0850f, -0.0051f}, {35.0f, 60.0f, 70.0f}}, // purple
+ {{0.6448f, 0.4828f, 1.7488f}, {75.0f, 45.0f, -100.0f}}, // lile
+ {{0.92f, 0.4828f, 0.0469f}, {75.0f, 100.0f, 80.0f}}}; // red
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_x, input_y, input_z] = color_pair.input;
+ auto [expected_l, expected_a, expected_b] = color_pair.expected;
+ auto [output_l, output_a, output_b] =
+ XYZD50ToLab(input_x, input_y, input_z);
+ EXPECT_NEAR(output_l, expected_l, 0.1f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_l
+ << ' ' << expected_a << ' ' << expected_b << " produced " << output_l
+ << ' ' << output_a << ' ' << output_b;
+ EXPECT_NEAR(output_a, expected_a, 0.1f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_l
+ << ' ' << expected_a << ' ' << expected_b << " produced " << output_l
+ << ' ' << output_a << ' ' << output_b;
+ EXPECT_NEAR(output_b, expected_b, 0.1f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_l
+ << ' ' << expected_a << ' ' << expected_b << " produced " << output_l
+ << ' ' << output_a << ' ' << output_b;
+ }
+}
+
+TEST(ColorConversions, OklabToXYZD65) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=lime&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{100.0f, 0.0, 0.0f},
+ {0.9504559270516717f, 1.0f, 1.0890577507598784f}}, // white
+ {{86.64396115356694f, -0.23388757418790818f, 0.17949847989672985f},
+ {0.357584339383878f, 0.715168678767756f, 0.11919477979462598f}}, // lime
+ {{42.09136612058102f, 0.16470430417002319f, -0.10147178154592906f},
+ {0.1279775574172914f, 0.06148383144929487f,
+ 0.20935510595451154f}}, // purple
+ {{48.06125447400232f, 0.1440294785250731f, 0.0688902950420287f},
+ {0.167625056565021f, 0.09823806119130823f,
+ 0.03204123425728893f}}, // brown
+ {{51.97518277948419f, -0.14030232755310995f, 0.10767589774360209f},
+ {0.07718833433230218f, 0.15437666866460437f,
+ 0.025729444777434055f}}}; // green
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_l, input_a, input_b] = color_pair.input;
+ auto [expected_x, expected_y, expected_z] = color_pair.expected;
+ auto [output_x, output_y, output_z] =
+ OklabToXYZD65(input_l, input_a, input_b);
+ EXPECT_NEAR(output_x, expected_x, 0.001f)
+ << input_l << ' ' << input_a << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_y, expected_y, 0.001f)
+ << input_l << ' ' << input_a << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_z, expected_z, 0.001f)
+ << input_l << ' ' << input_a << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ }
+}
+
+TEST(ColorConversions, XYZD65ToOklab) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=lime&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.9504559270516717f, 1.0f, 1.0890577507598784f},
+ {100.0f, 0.0, 0.0f}}, // white
+ {{0.357584339383878f, 0.715168678767756f, 0.11919477979462598f},
+ {86.64396115356694f, -0.23388757418790818f,
+ 0.17949847989672985f}}, // lime
+ {{0.1279775574172914f, 0.06148383144929487f, 0.20935510595451154f},
+ {42.09136612058102f, 0.16470430417002319f,
+ -0.10147178154592906f}}, // purple
+ {{0.167625056565021f, 0.09823806119130823f, 0.03204123425728893f},
+ {48.06125447400232f, 0.1440294785250731f,
+ 0.0688902950420287f}}, // brown
+ {{0.07718833433230218f, 0.15437666866460437f, 0.025729444777434055f},
+ {51.97518277948419f, -0.14030232755310995f,
+ 0.10767589774360209f}}}; // green
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_l, input_a, input_b] = color_pair.input;
+ auto [expected_x, expected_y, expected_z] = color_pair.expected;
+ auto [output_x, output_y, output_z] =
+ XYZD65ToOklab(input_l, input_a, input_b);
+ EXPECT_NEAR(output_x, expected_x, 0.001f)
+ << input_l << ' ' << input_a << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_y, expected_y, 0.001f)
+ << input_l << ' ' << input_a << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_z, expected_z, 0.001f)
+ << input_l << ' ' << input_a << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ }
+}
+
+TEST(ColorConversions, XYZD50ToD65) {
+ // Color conversions obtained from
+ // https://www.nixsensor.com/free-color-converter/
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.95047f, 1.0f, 1.0888f}, {0.95392f, 1.00594f, 1.439698f}}, // white
+ {{0.412, 0.213f, 0.019f}, {0.389938f, 0.20384f, 0.025982f}},
+ {{0.358f, 0.715f, 0.119f}, {0.33307f, 0.714494f, 0.1480589f}},
+ {{0.18f, 0.072f, 0.95f}, {0.23041847f, 0.087602f, 1.264587f}},
+ {{0.23f, 0.107f, 0.555f}, {0.252396f, 0.113222f, 0.73899f}},
+ {{0.114f, 0.09f, 0.087f}, {0.112348f, 0.089496f, 0.115299f}}};
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_x, input_y, input_z] = color_pair.input;
+ auto [expected_x, expected_y, expected_z] = color_pair.expected;
+ auto [output_x, output_y, output_z] =
+ XYZD50ToD65(input_x, input_y, input_z);
+ EXPECT_NEAR(output_x, expected_x, 0.001f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_y, expected_y, 0.001f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_z, expected_z, 0.001f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ }
+}
+
+TEST(ColorConversions, XYZD65ToD50) {
+ // Color conversions obtained from
+ // https://www.nixsensor.com/free-color-converter/
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.95392f, 1.00594f, 1.439698f}, {0.95047f, 1.0f, 1.0888f}}, // white
+ {{0.389938f, 0.20384f, 0.025982f}, {0.412, 0.213f, 0.019f}},
+ {{0.33307f, 0.714494f, 0.1480589f}, {0.358f, 0.715f, 0.119f}},
+ {{0.23041847f, 0.087602f, 1.264587f}, {0.18f, 0.072f, 0.95f}},
+ {{0.252396f, 0.113222f, 0.73899f}, {0.23f, 0.107f, 0.555f}},
+ {{0.112348f, 0.089496f, 0.115299f}, {0.114f, 0.09f, 0.087f}}};
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_x, input_y, input_z] = color_pair.input;
+ auto [expected_x, expected_y, expected_z] = color_pair.expected;
+ auto [output_x, output_y, output_z] =
+ XYZD65ToD50(input_x, input_y, input_z);
+ EXPECT_NEAR(output_x, expected_x, 0.001f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_y, expected_y, 0.001f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_z, expected_z, 0.001f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ }
+}
+
+TEST(ColorConversions, XYZD50TosRGBLinear) {
+ // Color conversions obtained from
+ // https://www.nixsensor.com/free-color-converter/
+ std::tuple<float, float, float> colors_tests[] = {
+ {0.0f, 0.0f, 0.0f}, // black
+ {0.95047f, 1.0f, 1.0888f}, // white
+ {0.412, 0.213f, 0.019f}, {0.358f, 0.715f, 0.119f},
+ {0.18f, 0.072f, 0.95f}, {0.23f, 0.107f, 0.555f},
+ {0.114f, 0.09f, 0.087f}};
+
+ for (auto [input_x, input_y, input_z] : colors_tests) {
+ auto [output_r, output_g, output_b] =
+ XYZD50TosRGBLinear(input_x, input_y, input_z);
+ auto [x, y, z] = XYZD50ToD65(input_x, input_y, input_z);
+ auto [expected_r, expected_g, expected_b] = XYZD65TosRGBLinear(x, y, z);
+ EXPECT_NEAR(output_r, expected_r, 0.1f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << output_r
+ << ' ' << output_g << ' ' << output_b;
+ EXPECT_NEAR(output_g, expected_g, 0.1f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << output_r
+ << ' ' << output_g << ' ' << output_b;
+ EXPECT_NEAR(output_b, expected_b, 0.1f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << output_r
+ << ' ' << output_g << ' ' << output_b;
+ }
+}
+
+TEST(ColorConversions, LchToLab) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{89.11f, 69.04f, 161.5f},
+ {89.11f, -65.472265155436f, 21.906713478207564f}},
+ {{29.6915239933531f, 66.82572352143814f, 327.1054738802461f},
+ {29.6915239933531f, 56.11167248735513f,
+ -36.292665028011974f}}, // purple
+ {{38.14895894517021f, 59.598372928277406f, 32.286662896162966f},
+ {38.14895894517021f, 50.38364171345111f, 31.834803335164764f}}, // brown
+ {{46.27770902748027f, 67.9842594463414f, 134.3838583288382f},
+ {46.27770902748027f, -47.55240796497723f,
+ 48.586294664234586f}}}; // green
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_l, input_c, input_h] = color_pair.input;
+ auto [expected_l, expected_a, expected_b] = color_pair.expected;
+ auto [output_l, output_a, output_b] =
+ LchToLab(input_l, input_c, absl::optional<float>(input_h));
+ EXPECT_NEAR(output_l, expected_l, 0.001f)
+ << input_l << ' ' << input_c << ' ' << input_h << " to " << expected_l
+ << ' ' << expected_a << ' ' << expected_b << " produced " << output_l
+ << ' ' << output_a << ' ' << output_b;
+ EXPECT_NEAR(output_a, expected_a, 0.001f)
+ << input_l << ' ' << input_c << ' ' << input_h << " to " << expected_l
+ << ' ' << expected_a << ' ' << expected_b << " produced " << output_l
+ << ' ' << output_a << ' ' << output_b;
+ EXPECT_NEAR(output_b, expected_b, 0.001f)
+ << input_l << ' ' << input_c << ' ' << input_h << " to " << expected_l
+ << ' ' << expected_a << ' ' << expected_b << " produced " << output_l
+ << ' ' << output_a << ' ' << output_b;
+ }
+
+ // Try with a none hue value (white).
+ float input_l = 100.0f;
+ float input_c = 0.000010331815288315629f;
+ absl::optional<float> input_h = absl::nullopt;
+ float expected_l = 100.0f;
+ float expected_a = -0.000007807961277528364f;
+ float expected_b = 0.000006766250648659877f;
+ auto [output_l, output_a, output_b] =
+ LchToLab(input_l, input_c, absl::optional<float>(input_h));
+ EXPECT_NEAR(output_l, expected_l, 0.001f)
+ << input_l << ' ' << input_c << ' ' << "none"
+ << " to " << expected_l << ' ' << expected_a << ' ' << expected_b
+ << " produced " << output_l << ' ' << output_a << ' ' << output_b;
+ EXPECT_NEAR(output_a, expected_a, 0.001f)
+ << input_l << ' ' << input_c << ' ' << "none"
+ << " to " << expected_l << ' ' << expected_a << ' ' << expected_b
+ << " produced " << output_l << ' ' << output_a << ' ' << output_b;
+ EXPECT_NEAR(output_b, expected_b, 0.001f)
+ << input_l << ' ' << input_c << ' ' << "none"
+ << " to " << expected_l << ' ' << expected_a << ' ' << expected_b
+ << " produced " << output_l << ' ' << output_a << ' ' << output_b;
+}
+
+TEST(ColorConversions, LabToLch) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{100.0f, 0.0f, 0.0f}, {100.0f, 0.0f, 0.0f}},
+ {{89.11f, -65.472265155436f, 21.906713478207564f},
+ {89.11f, 69.04f, 161.5f}},
+ {{29.6915239933531f, 56.11167248735513f, -36.292665028011974f},
+ {29.6915239933531f, 66.82572352143814f,
+ -32.894523620605469f}}, // purple
+ {{38.14895894517021f, 50.38364171345111f, 31.834803335164764f},
+ {38.14895894517021f, 59.598372928277406f,
+ 32.286662896162966f}}, // brown
+ {{46.27770902748027f, -47.55240796497723f, 48.586294664234586f},
+ {46.27770902748027f, 67.9842594463414f, 134.3838583288382f}}}; // green
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_l, input_a, input_b] = color_pair.input;
+ auto [expected_l, expected_c, expected_h] = color_pair.expected;
+ auto [output_l, output_c, output_h] = LabToLch(input_l, input_a, input_b);
+ EXPECT_NEAR(output_l, expected_l, 0.001f)
+ << input_l << ' ' << input_a << ' ' << input_b << " to " << expected_l
+ << ' ' << expected_c << ' ' << expected_h << " produced " << output_l
+ << ' ' << output_c << ' ' << output_h;
+ EXPECT_NEAR(output_c, expected_c, 0.001f)
+ << input_l << ' ' << input_a << ' ' << input_b << " to " << expected_l
+ << ' ' << expected_c << ' ' << expected_h << " produced " << output_l
+ << ' ' << output_c << ' ' << output_h;
+ EXPECT_NEAR(output_h, expected_h, 0.001f)
+ << input_l << ' ' << input_a << ' ' << input_b << " to " << expected_l
+ << ' ' << expected_c << ' ' << expected_h << " produced " << output_l
+ << ' ' << output_c << ' ' << output_h;
+ }
+}
+
+TEST(ColorConversions, LchToSkColor4f) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{87.81853633115202f, 113.33150206540324f, 134.38385832883824f},
+ {0.0f, 1.0f, 0.0f}}, // lime
+ {{29.6915239933531f, 66.82572352143814f, 327.1054738802461f},
+ {0.5019607843137255f, 0.0f, 0.5019607843137255f}}, // purple
+ {{38.14895894517021f, 59.598372928277406f, 32.286662896162966f},
+ {0.6470588235294118f, 0.16470588235294117f,
+ 0.16470588235294117f}}, // brown
+ {{46.27770902748027f, 67.9842594463414f, 134.3838583288382f},
+ {0.0f, 0.5019607843137255f, 0.0f}}}; // green
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_l, input_c, input_h] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ SkColor4f color =
+ LchToSkColor4f(input_l, input_c, absl::optional<float>(input_h), 1.0f);
+ EXPECT_NEAR(color.fR, expected_r, 0.01f)
+ << input_l << ' ' << input_c << ' ' << input_h << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fG, expected_g, 0.01f)
+ << input_l << ' ' << input_c << ' ' << input_h << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fB, expected_b, 0.01f)
+ << input_l << ' ' << input_c << ' ' << input_h << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ }
+
+ // Try with a none hue value (white).
+ float input_l = 100.0f;
+ float input_c = 0.000010331815288315629f;
+ absl::optional<float> input_h = absl::nullopt;
+ float expected_r = 1.0f;
+ float expected_g = 1.0f;
+ float expected_b = 1.0f;
+ SkColor4f color =
+ LchToSkColor4f(input_l, input_c, absl::optional<float>(input_h), 1.0f);
+ EXPECT_NEAR(color.fR, expected_r, 0.001f)
+ << input_l << ' ' << input_c << ' ' << "none"
+ << " to " << expected_r << ' ' << expected_g << ' ' << expected_b
+ << " produced " << color.fR << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fG, expected_g, 0.001f)
+ << input_l << ' ' << input_c << ' ' << "none"
+ << " to " << expected_r << ' ' << expected_g << ' ' << expected_b
+ << " produced " << color.fR << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fB, expected_b, 0.001f)
+ << input_l << ' ' << input_c << ' ' << "none"
+ << " to " << expected_r << ' ' << expected_g << ' ' << expected_b
+ << " produced " << color.fR << ' ' << color.fG << ' ' << color.fB;
+}
+
+TEST(ColorConversions, OklchToSkColor4f) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{86.64396115356694f, 0.2948272403370167f, 142.49533888780996f},
+ {0.0f, 1.0f, 0.0f}}, // lime
+ {{42.09136612058102f, 0.19345291484554133f, 328.36341792345144f},
+ {0.5019607843137255f, 0.0f, 0.5019607843137255f}}, // purple
+ {{48.06125447400232f, 0.1596570181206647f, 25.562112067668068f},
+ {0.6470588235294118f, 0.16470588235294117f,
+ 0.16470588235294117f}}, // brown
+ {{51.97518277948419f, 0.17685825418032036f, 142.4953388878099f},
+ {0.0f, 0.5019607843137255f, 0.0f}}}; // green
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_l, input_c, input_h] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ SkColor4f color = OklchToSkColor4f(input_l, input_c,
+ absl::optional<float>(input_h), 1.0f);
+ EXPECT_NEAR(color.fR, expected_r, 0.01f)
+ << input_l << ' ' << input_c << ' ' << input_h << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fG, expected_g, 0.01f)
+ << input_l << ' ' << input_c << ' ' << input_h << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fB, expected_b, 0.01f)
+ << input_l << ' ' << input_c << ' ' << input_h << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ }
+
+ // Try with a none hue value (white).
+ float input_l = 100.0f;
+ float input_c = 0.000010331815288315629f;
+ absl::optional<float> input_h = absl::nullopt;
+ float expected_r = 1.0f;
+ float expected_g = 1.0f;
+ float expected_b = 1.0f;
+ SkColor4f color =
+ OklchToSkColor4f(input_l, input_c, absl::optional<float>(input_h), 1.0f);
+ EXPECT_NEAR(color.fR, expected_r, 0.001f)
+ << input_l << ' ' << input_c << ' ' << "none"
+ << " to " << expected_r << ' ' << expected_g << ' ' << expected_b
+ << " produced " << color.fR << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fG, expected_g, 0.001f)
+ << input_l << ' ' << input_c << ' ' << "none"
+ << " to " << expected_r << ' ' << expected_g << ' ' << expected_b
+ << " produced " << color.fR << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fB, expected_b, 0.001f)
+ << input_l << ' ' << input_c << ' ' << "none"
+ << " to " << expected_r << ' ' << expected_g << ' ' << expected_b
+ << " produced " << color.fR << ' ' << color.fG << ' ' << color.fB;
+}
+
+TEST(ColorConversions, SRGBLinearToXYZD50) {
+ // Color conversions obtained from
+ // https://www.nixsensor.com/free-color-converter/
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{1.0f, 1.0f, 1.0f},
+ {0.9642956660812443f, 1.0000000361162846f,
+ 0.8251045485672053f}}, // white
+ {{0.0f, 1.0f, 0.0f},
+ {0.3851514688337912f, 0.7168870538238823f,
+ 0.09708128566574631f}}, // lime
+ {{0.37626212299090644f, 0.02315336617811041f, 0.02315336617811041f},
+ {0.1763053229982614f, 0.10171766135467991f,
+ 0.024020600356509242f}}, // brown
+ {{1.0f, 0.5271151257058131f, 0.5972017883637634f},
+ {0.7245316165924385f, 0.6365774485679174f,
+ 0.4915583325045292f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_r, input_g, input_b] = color_pair.input;
+ auto [expected_x, expected_y, expected_z] = color_pair.expected;
+ auto [output_x, output_y, output_z] =
+ SRGBLinearToXYZD50(input_r, input_g, input_b);
+ EXPECT_NEAR(output_x, expected_x, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_y, expected_y, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_z, expected_z, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ }
+}
+
+TEST(ColorConversions, SRGBToXYZD50) {
+ // Color conversions obtained from
+ // https://www.nixsensor.com/free-color-converter/
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{1.0f, 1.0f, 1.0f},
+ {0.9642956660812443f, 1.0000000361162846f,
+ 0.8251045485672053f}}, // white
+ {{0.0f, 1.0f, 0.0f},
+ {0.3851514688337912f, 0.7168870538238823f,
+ 0.09708128566574631f}}, // lime
+ {{0.6470588235294118f, 0.16470588235294117f, 0.16470588235294117f},
+ {0.1763053229982614f, 0.10171766135467991f,
+ 0.024020600356509242f}}, // brown
+ {{1.0f, 0.7529411764705882f, 0.796078431372549f},
+ {0.7245316165924385f, 0.6365774485679174f,
+ 0.4915583325045292f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_r, input_g, input_b] = color_pair.input;
+ auto [expected_x, expected_y, expected_z] = color_pair.expected;
+ auto [output_x, output_y, output_z] =
+ SRGBToXYZD50(input_r, input_g, input_b);
+ EXPECT_NEAR(output_x, expected_x, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_y, expected_y, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_z, expected_z, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ }
+}
+
+TEST(ColorConversions, SRGBToHSL) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{1.0f, 1.0f, 1.0f}, {0.0f, 0.f, 1.f}}, // white
+ {{0.0f, 1.0f, 0.0f}, {120.0f / 60.0f, 1.0f, 0.5f}}, // lime
+ {{0.6470588235294118f, 0.16470588235294117f, 0.16470588235294117f},
+ {0.0f, 0.59420289855072475f, 0.40588235294117645f}}, // brown
+ {{0.5019607843137255f, 0.0f, 0.5019607843137255f},
+ {300.0f / 60.0f, 1.0f, 0.250980392156862741f}}, // purple
+ {{1.0f, 0.7529411764705882f, 0.796078431372549f},
+ {349.5238095238096f / 60.0f, 1.00f, 0.876470588235294f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_r, input_g, input_b] = color_pair.input;
+ auto [expected_h, expected_s, expected_l] = color_pair.expected;
+ auto [output_h, output_s, output_l] = SRGBToHSL(input_r, input_g, input_b);
+ EXPECT_NEAR(output_h, expected_h, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_h
+ << ' ' << expected_s << ' ' << expected_l << " produced " << output_h
+ << ' ' << output_s << ' ' << output_l;
+ EXPECT_NEAR(output_s, expected_s, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_h
+ << ' ' << expected_s << ' ' << expected_l << " produced " << output_h
+ << ' ' << output_s << ' ' << output_l;
+ EXPECT_NEAR(output_l, expected_l, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_h
+ << ' ' << expected_s << ' ' << expected_l << " produced " << output_h
+ << ' ' << output_s << ' ' << output_l;
+ }
+}
+
+TEST(ColorConversions, SRGBToHWB) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f}}, // black
+ {{1.0f, 1.0f, 1.0f}, {0.0f, 1.f, 0.f}}, // white
+ {{0.5, 0.5, 0.5}, {0.0f, 0.5f, 0.5f}}, // grey
+ {{0.0f, 1.0f, 0.0f}, {120.0f / 60.0f, 0.0f, 0.0f}}, // lime
+ {{0.6470588235294118f, 0.16470588235294117f, 0.16470588235294117f},
+ {0.0f, 0.1647058823529411f, 0.35294117647058826f}}, // brown
+ {{0.5019607843137255f, 0.0f, 0.5019607843137255f},
+ {300.0f / 60.0f, 0.0f, 0.4980392156862745f}}, // purple
+ {{1.0f, 0.7529411764705882f, 0.796078431372549f},
+ {349.5238095238096f / 60.0f, 0.7529411764705883f, 0.0f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_r, input_g, input_b] = color_pair.input;
+ auto [expected_h, expected_w, expected_b] = color_pair.expected;
+ auto [output_h, output_w, output_b] = SRGBToHWB(input_r, input_g, input_b);
+ EXPECT_NEAR(output_h, expected_h, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_h
+ << ' ' << expected_w << ' ' << expected_b << " produced " << output_h
+ << ' ' << output_w << ' ' << output_b;
+ EXPECT_NEAR(output_w, expected_w, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_h
+ << ' ' << expected_w << ' ' << expected_b << " produced " << output_h
+ << ' ' << output_w << ' ' << output_b;
+ EXPECT_NEAR(output_b, expected_b, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_h
+ << ' ' << expected_w << ' ' << expected_b << " produced " << output_h
+ << ' ' << output_w << ' ' << output_b;
+ }
+}
+
+TEST(ColorConversions, XYZD50ToSkColor4f) {
+ // Color conversions obtained from
+ // https://www.nixsensor.com/free-color-converter/
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.9642956660812443f, 1.0000000361162846f, 0.8251045485672053f},
+ {1.0f, 1.0f, 1.0f}}, // white
+ {{0.3851514688337912f, 0.7168870538238823f, 0.09708128566574631f},
+ {0.0f, 1.0f, 0.0f}}, // lime
+ {{0.1763053229982614f, 0.10171766135467991f, 0.024020600356509242f},
+ {0.6470588235294118f, 0.16470588235294117f,
+ 0.16470588235294117f}}, // brown
+ {{0.7245316165924385f, 0.6365774485679174f, 0.4915583325045292f},
+ {1.0f, 0.7529411764705882f, 0.796078431372549f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_x, input_y, input_z] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ SkColor4f color = XYZD50ToSkColor4f(input_x, input_y, input_z, 1.0f);
+ EXPECT_NEAR(color.fR, expected_r, 0.01f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fG, expected_g, 0.01f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fB, expected_b, 0.01f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ }
+}
+
+TEST(ColorConversions, XYZD65ToSkColor4f) {
+ // Color conversions obtained from
+ // https://www.nixsensor.com/free-color-converter/
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.9504559270516717f, 1.f, 1.0890577507598784f},
+ {1.0f, 1.0f, 1.0f}}, // white
+ {{0.357584339383878f, 0.715168678767756f, 0.11919477979462598f},
+ {0.0f, 1.0f, 0.0f}}, // lime
+ {{0.167625056565021f, 0.09823806119130823f, 0.032041234257288932f},
+ {0.6470588235294118f, 0.16470588235294117f,
+ 0.16470588235294117f}}, // brown
+ {{0.7086623628695997f, 0.6327286137205872f, 0.6498196912712672f},
+ {1.0f, 0.7529411764705882f, 0.796078431372549f}}, // pink
+ {{1.0f, 1.0f, 1.0f}, {1.085f, 0.9769f, 0.9587f}}};
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_x, input_y, input_z] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ SkColor4f color = XYZD65ToSkColor4f(input_x, input_y, input_z, 1.0f);
+ EXPECT_NEAR(color.fR, expected_r, 0.01f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fG, expected_g, 0.01f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fB, expected_b, 0.01f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ }
+}
+
+TEST(ColorConversions, LabToSkColor4f) {
+ // Color conversions obtained from
+ // https://www.nixsensor.com/free-color-converter/
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{100.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}}, // white
+ {{46.2775f, -47.521f, 48.5837f}, {0.0f, 0.5f, 0.0f}}, // green
+ {{50.0f, 50.0f, 0.0f}, {0.756208f, 0.304487f, 0.475634f}},
+ {{70.0f, -45.0f, 0.0f}, {0.10751f, 0.75558f, 0.66398f}},
+ {{70.0f, 0.0f, 70.0f}, {0.766254f, 0.663607f, 0.055775f}},
+ {{55.0f, 0.0f, -60.0f}, {0.128128f, 0.53105f, 0.927645f}},
+ {{100.115f, 9.06448f, 5.80177f}, {1.085f, 0.9769f, 0.9587f}}};
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_l, input_a, input_b] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ SkColor4f color = LabToSkColor4f(input_l, input_a, input_b, 1.0f);
+ EXPECT_NEAR(color.fR, expected_r, 0.01f)
+ << input_l << ' ' << input_a << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fG, expected_g, 0.01f)
+ << input_l << ' ' << input_a << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fB, expected_b, 0.01f)
+ << input_l << ' ' << input_a << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ }
+}
+
+TEST(ColorConversions, SRGBLinearToSkColor4f) {
+ // Color conversions obtained from
+ // https://www.nixsensor.com/free-color-converter/
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f}}, // white
+ {{0.f, 0.21586050011389923f, 0.f},
+ {0.f, 0.5019607843137255f, 0.f}}, // green
+ {{0.21586050011389923f, 0.f, 0.21586050011389923f},
+ {0.5019607843137255f, 0.f, 0.5019607843137255f}}, // purple
+ {{1.f, 0.5271151257058131f, 0.5972017883637634f},
+ {1.f, 0.7529411764705882f, 0.796078431372549f}}, // pink
+ {{0.37626212299090644f, 0.02315336617811041f, 0.02315336617811041f},
+ {0.6470588235294118f, 0.16470588235294117f,
+ 0.16470588235294117f}}}; // brown
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_r, input_g, input_b] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ SkColor4f color = SRGBLinearToSkColor4f(input_r, input_g, input_b, 1.0f);
+ EXPECT_NEAR(color.fR, expected_r, 0.01f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fG, expected_g, 0.01f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fB, expected_b, 0.01f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ }
+}
+
+TEST(ColorConversions, DisplayP3ToXYZD50) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.9999999999999999f, 0.9999999999999997f, 0.9999999999999999f},
+ {0.9642956660812443f, 1.0000000361162846f,
+ 0.8251045485672053f}}, // white
+ {{0.45840159019103005f, 0.9852645833250543f, 0.29829470783345835f},
+ {0.3851514688337912f, 0.7168870538238823f,
+ 0.09708128566574631f}}, // lime
+ {{0.5957181607237907f, 0.2055939145569215f, 0.18695695018247227f},
+ {0.1763053229982614f, 0.10171766135467991f,
+ 0.024020600356509242f}}, // brown
+ {{0.4584004101072638f, 0.07977226603250179f, 0.4847907338567859f},
+ {0.1250143560558979f, 0.0611129099463755f,
+ 0.15715146562446167f}}, // purple
+ {{0.962148711796773f, 0.7628803605364196f, 0.7971503318758075f},
+ {0.7245316165924385f, 0.6365774485679174f,
+ 0.4915583325045292f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_r, input_g, input_b] = color_pair.input;
+ auto [expected_x, expected_y, expected_z] = color_pair.expected;
+ auto [output_x, output_y, output_z] =
+ DisplayP3ToXYZD50(input_r, input_g, input_b);
+ EXPECT_NEAR(output_x, expected_x, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_y, expected_y, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_z, expected_z, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ }
+}
+
+TEST(ColorConversions, XYZD50ToDisplayP3) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.9642956660812443f, 1.0000000361162846f, 0.8251045485672053f},
+ {0.9999999999999999f, 0.9999999999999997f,
+ 0.9999999999999999f}}, // white
+ {{0.3851514688337912f, 0.7168870538238823f, 0.09708128566574631f},
+ {0.45840159019103005f, 0.9852645833250543f,
+ 0.29829470783345835f}}, // lime
+ {{0.1763053229982614f, 0.10171766135467991f, 0.024020600356509242f},
+ {0.5957181607237907f, 0.2055939145569215f,
+ 0.18695695018247227f}}, // brown
+ {{0.1250143560558979f, 0.0611129099463755f, 0.15715146562446167f},
+ {0.4584004101072638f, 0.07977226603250179f,
+ 0.4847907338567859f}}, // purple
+ {{0.7245316165924385f, 0.6365774485679174f, 0.4915583325045292f},
+ {0.962148711796773f, 0.7628803605364196f,
+ 0.7971503318758075f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_x, input_y, input_z] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ auto [output_r, output_g, output_b] =
+ XYZD50ToDisplayP3(input_x, input_y, input_z);
+ EXPECT_NEAR(output_r, expected_r, 0.001f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << output_r
+ << ' ' << output_g << ' ' << output_b;
+ EXPECT_NEAR(output_g, expected_g, 0.001f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << output_r
+ << ' ' << output_g << ' ' << output_b;
+ EXPECT_NEAR(output_b, expected_b, 0.001f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << output_r
+ << ' ' << output_g << ' ' << output_b;
+ }
+}
+
+TEST(ColorConversions, DisplayP3ToSkColor4f) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.9999999999999999f, 0.9999999999999997f, 0.9999999999999999f},
+ {1.0f, 1.0f, 1.0f}}, // white
+ {{0.45840159019103005f, 0.9852645833250543f, 0.29829470783345835f},
+ {0.0f, 1.0f, 0.0f}}, // lime
+ {{0.5957181607237907f, 0.2055939145569215f, 0.18695695018247227f},
+ {0.6470588235294118f, 0.16470588235294117f,
+ 0.16470588235294117f}}, // brown
+ {{0.4584004101072638f, 0.07977226603250179f, 0.4847907338567859f},
+ {0.5019607843137255f, 0.0f, 0.5019607843137255f}}, // purple
+ {{0.962148711796773f, 0.7628803605364196f, 0.7971503318758075f},
+ {1.0f, 0.7529411764705882f, 0.796078431372549f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_r, input_g, input_b] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ SkColor4f color = DisplayP3ToSkColor4f(input_r, input_g, input_b, 1.0f);
+ EXPECT_NEAR(color.fR, expected_r, 0.01f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fG, expected_g, 0.01f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fB, expected_b, 0.01f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ }
+}
+
+TEST(ColorConversions, ProPhotoToXYZD50) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=pink&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.9999999886663737f, 1.0000000327777285f, 0.9999999636791804f},
+ {0.9642956660812443f, 1.0000000361162846f,
+ 0.8251045485672053f}}, // white
+ {{0.5402807890930262f, 0.9275948938161531f, 0.30456598218387576f},
+ {0.3851514688337912f, 0.7168870538238823f,
+ 0.09708128566574631f}}, // lime
+ {{0.4202512875251534f, 0.20537448341387265f, 0.14018716364460992f},
+ {0.1763053229982614f, 0.10171766135467991f,
+ 0.024020600356509242f}}, // brown
+ {{0.3415199027593793f, 0.13530888280806527f, 0.3980101298732242f},
+ {0.1250143560558979f, 0.0611129099463755f,
+ 0.15715146562446167f}}, // purple
+ {{0.8755612852965058f, 0.7357597566543541f, 0.7499575746802042f},
+ {0.7245316165924385f, 0.6365774485679174f,
+ 0.4915583325045292f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_r, input_g, input_b] = color_pair.input;
+ auto [expected_x, expected_y, expected_z] = color_pair.expected;
+ auto [output_x, output_y, output_z] =
+ ProPhotoToXYZD50(input_r, input_g, input_b);
+ EXPECT_NEAR(output_x, expected_x, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_y, expected_y, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_z, expected_z, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ }
+}
+
+TEST(ColorConversions, XYZD50ToProPhoto) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=pink&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.9642956660812443f, 1.0000000361162846f, 0.8251045485672053f},
+ {0.9999999886663737f, 1.0000000327777285f,
+ 0.9999999636791804f}}, // white
+ {{0.3851514688337912f, 0.7168870538238823f, 0.09708128566574631f},
+ {0.5402807890930262f, 0.9275948938161531f,
+ 0.30456598218387576f}}, // lime
+ {{0.1763053229982614f, 0.10171766135467991f, 0.024020600356509242f},
+ {0.4202512875251534f, 0.20537448341387265f,
+ 0.14018716364460992f}}, // brown
+ {{0.1250143560558979f, 0.0611129099463755f, 0.15715146562446167f},
+ {0.3415199027593793f, 0.13530888280806527f,
+ 0.3980101298732242f}}, // purple
+ {{0.7245316165924385f, 0.6365774485679174f, 0.4915583325045292f},
+ {0.8755612852965058f, 0.7357597566543541f,
+ 0.7499575746802042f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_x, input_y, input_z] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ auto [output_r, output_g, output_b] =
+ XYZD50ToProPhoto(input_x, input_y, input_z);
+ EXPECT_NEAR(output_r, expected_r, 0.001f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << output_r
+ << ' ' << output_g << ' ' << output_b;
+ EXPECT_NEAR(output_g, expected_g, 0.001f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << output_r
+ << ' ' << output_g << ' ' << output_b;
+ EXPECT_NEAR(output_b, expected_b, 0.001f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << output_r
+ << ' ' << output_g << ' ' << output_b;
+ }
+}
+
+TEST(ColorConversions, ProPhotoToSkColor4f) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=pink&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.9999999886663737f, 1.0000000327777285f, 0.9999999636791804f},
+ {1.0f, 1.0f, 1.0f}}, // white
+ {{0.5402807890930262f, 0.9275948938161531f, 0.30456598218387576f},
+ {0.0f, 1.0f, 0.0f}}, // lime
+ {{0.4202512875251534f, 0.20537448341387265f, 0.14018716364460992f},
+ {0.6470588235294118f, 0.16470588235294117f,
+ 0.16470588235294117f}}, // brown
+ {{0.3415199027593793f, 0.13530888280806527f, 0.3980101298732242f},
+ {0.5019607843137255f, 0.0f, 0.5019607843137255f}}, // purple
+ {{0.8755612852965058f, 0.7357597566543541f, 0.7499575746802042f},
+ {1.0f, 0.7529411764705882f, 0.796078431372549f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_r, input_g, input_b] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ SkColor4f color = ProPhotoToSkColor4f(input_r, input_g, input_b, 1.0f);
+ EXPECT_NEAR(color.fR, expected_r, 0.01f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fG, expected_g, 0.01f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fB, expected_b, 0.01f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ }
+}
+
+TEST(ColorConversions, AdobeRGBToXYZD50) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{1.0000000000000002f, 0.9999999999999999f, 1.f},
+ {0.9642956660812443f, 1.0000000361162846f,
+ 0.8251045485672053f}}, // white
+ {{0.564972265988564f, 0.9999999999999999f, 0.23442379872902916f},
+ {0.3851514688337912f, 0.7168870538238823f,
+ 0.09708128566574631f}}, // lime
+ {{0.5565979160264471f, 0.18045907254050694f, 0.18045907254050705f},
+ {0.1763053229982614f, 0.10171766135467991f,
+ 0.024020600356509242f}}, // brown
+ {{0.4275929819700999f, 0.0f, 0.4885886519419426f},
+ {0.1250143560558979f, 0.0611129099463755f,
+ 0.15715146562446167f}}, // purple
+ {{0.9363244100721754f, 0.7473920857106169f, 0.7893042668092753f},
+ {0.7245316165924385f, 0.6365774485679174f,
+ 0.4915583325045292f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_r, input_g, input_b] = color_pair.input;
+ auto [expected_x, expected_y, expected_z] = color_pair.expected;
+ auto [output_x, output_y, output_z] =
+ AdobeRGBToXYZD50(input_r, input_g, input_b);
+ EXPECT_NEAR(output_x, expected_x, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_y, expected_y, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_z, expected_z, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ }
+}
+
+TEST(ColorConversions, XYZD50ToAdobeRGB) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.9642956660812443f, 1.0000000361162846f, 0.8251045485672053f},
+ {1.0000000000000002f, 0.9999999999999999f, 1.f}}, // white
+ {{0.3851514688337912f, 0.7168870538238823f, 0.09708128566574631f},
+ {0.564972265988564f, 0.9999999999999999f,
+ 0.23442379872902916f}}, // lime
+ {{0.1763053229982614f, 0.10171766135467991f, 0.024020600356509242f},
+ {0.5565979160264471f, 0.18045907254050694f,
+ 0.18045907254050705f}}, // brown
+ {{0.1250143560558979f, 0.0611129099463755f, 0.15715146562446167f},
+ {0.4275929819700999f, 0.0f, 0.4885886519419426f}}, // purple
+ {{0.7245316165924385f, 0.6365774485679174f, 0.4915583325045292f},
+ {0.9363244100721754f, 0.7473920857106169f,
+ 0.7893042668092753f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_x, input_y, input_z] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ auto [output_r, output_g, output_b] =
+ XYZD50ToAdobeRGB(input_x, input_y, input_z);
+ EXPECT_NEAR(output_r, expected_r, 0.01f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << output_r
+ << ' ' << output_g << ' ' << output_b;
+ EXPECT_NEAR(output_g, expected_g, 0.01f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << output_r
+ << ' ' << output_g << ' ' << output_b;
+ EXPECT_NEAR(output_b, expected_b, 0.01f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << output_r
+ << ' ' << output_g << ' ' << output_b;
+ }
+}
+
+TEST(ColorConversions, AdobeRGBToSkColor4f) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{1.0000000000000002f, 0.9999999999999999f, 1.f},
+ {1.0f, 1.0f, 1.0f}}, // white
+ {{0.564972265988564f, 0.9999999999999999f, 0.23442379872902916f},
+ {0.0f, 1.0f, 0.0f}}, // lime
+ {{0.5565979160264471f, 0.18045907254050694f, 0.18045907254050705f},
+ {0.6470588235294118f, 0.16470588235294117f,
+ 0.16470588235294117f}}, // brown
+ {{0.4275929819700999f, 0.0f, 0.4885886519419426f},
+ {0.5019607843137255f, 0.0f, 0.5019607843137255f}}, // purple
+ {{0.9363244100721754f, 0.7473920857106169f, 0.7893042668092753f},
+ {1.0f, 0.7529411764705882f, 0.796078431372549f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_r, input_g, input_b] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ SkColor4f color = AdobeRGBToSkColor4f(input_r, input_g, input_b, 1.0f);
+ EXPECT_NEAR(color.fR, expected_r, 0.01f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fG, expected_g, 0.01f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fB, expected_b, 0.01f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ }
+}
+
+TEST(ColorConversions, Rec2020ToXYZD50) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{1.0000000000000002f, 1.f, 1.f},
+ {0.9642956660812443f, 1.0000000361162846f,
+ 0.8251045485672053f}}, // white
+ {{0.5675424725933591f, 0.959278677099374f, 0.2689692617052188f},
+ {0.3851514688337912f, 0.7168870538238823f,
+ 0.09708128566574631f}}, // lime
+ {{0.4841434514625542f, 0.17985588424119636f, 0.12395667053434403f},
+ {0.1763053229982614f, 0.10171766135467991f,
+ 0.024020600356509242f}}, // brown
+ {{0.36142160262090384f, 0.0781562275109019f, 0.429742223818931f},
+ {0.1250143560558979f, 0.0611129099463755f,
+ 0.15715146562446167f}}, // purple
+ {{0.9098509851821579f, 0.747938726996672f, 0.7726929727190115f},
+ {0.7245316165924385f, 0.6365774485679174f,
+ 0.4915583325045292f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_r, input_g, input_b] = color_pair.input;
+ auto [expected_x, expected_y, expected_z] = color_pair.expected;
+ auto [output_x, output_y, output_z] =
+ Rec2020ToXYZD50(input_r, input_g, input_b);
+ EXPECT_NEAR(output_x, expected_x, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_y, expected_y, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ EXPECT_NEAR(output_z, expected_z, 0.001f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_x
+ << ' ' << expected_y << ' ' << expected_z << " produced " << output_x
+ << ' ' << output_y << ' ' << output_z;
+ }
+}
+
+TEST(ColorConversions, XYZD50ToRec2020) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.9642956660812443f, 1.0000000361162846f, 0.8251045485672053f},
+ {1.0000000000000002f, 1.f, 1.f}}, // white
+ {{0.3851514688337912f, 0.7168870538238823f, 0.09708128566574631f},
+ {0.5675424725933591f, 0.959278677099374f, 0.2689692617052188f}}, // lime
+ {{0.1763053229982614f, 0.10171766135467991f, 0.024020600356509242f},
+ {0.4841434514625542f, 0.17985588424119636f,
+ 0.12395667053434403f}}, // brown
+ {{0.1250143560558979f, 0.0611129099463755f, 0.15715146562446167f},
+ {0.36142160262090384f, 0.0781562275109019f,
+ 0.429742223818931f}}, // purple
+ {{0.7245316165924385f, 0.6365774485679174f, 0.4915583325045292f},
+ {0.9098509851821579f, 0.747938726996672f,
+ 0.7726929727190115f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_x, input_y, input_z] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ auto [output_r, output_g, output_b] =
+ XYZD50ToRec2020(input_x, input_y, input_z);
+ EXPECT_NEAR(output_r, expected_r, 0.001f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << output_r
+ << ' ' << output_g << ' ' << output_b;
+ EXPECT_NEAR(output_g, expected_g, 0.001f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << output_r
+ << ' ' << output_g << ' ' << output_b;
+ EXPECT_NEAR(output_b, expected_b, 0.001f)
+ << input_x << ' ' << input_y << ' ' << input_z << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << output_r
+ << ' ' << output_g << ' ' << output_b;
+ }
+}
+
+TEST(ColorConversions, Rec2020ToSkColor4f) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{1.0000000000000002f, 1.f, 1.f}, {1.0f, 1.0f, 1.0f}}, // white
+ {{0.5675424725933591f, 0.959278677099374f, 0.2689692617052188f},
+ {0.0f, 1.0f, 0.0f}}, // lime
+ {{0.4841434514625542f, 0.17985588424119636f, 0.12395667053434403f},
+ {0.6470588235294118f, 0.16470588235294117f,
+ 0.16470588235294117f}}, // brown
+ {{0.36142160262090384f, 0.0781562275109019f, 0.429742223818931f},
+ {0.5019607843137255f, 0.0f, 0.5019607843137255f}}, // purple
+ {{0.9098509851821579f, 0.747938726996672f, 0.7726929727190115f},
+ {1.0f, 0.7529411764705882f, 0.796078431372549f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_r, input_g, input_b] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ SkColor4f color = Rec2020ToSkColor4f(input_r, input_g, input_b, 1.0f);
+ EXPECT_NEAR(color.fR, expected_r, 0.01f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fG, expected_g, 0.01f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fB, expected_b, 0.01f)
+ << input_r << ' ' << input_g << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ }
+}
+
+TEST(ColorConversions, HSLToSkColor4f) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.0f, 0.f, 1.f}, {1.0f, 1.0f, 1.0f}}, // white
+ {{120.0f / 60.0f, 1.0f, 0.5f}, {0.0f, 1.0f, 0.0f}}, // lime
+ {{0.0f, 0.59420289855072475f, 0.40588235294117645f},
+ {0.6470588235294118f, 0.16470588235294117f,
+ 0.16470588235294117f}}, // brown
+ {{300.0f / 60.0f, 1.0f, 0.250980392156862741f},
+ {0.5019607843137255f, 0.0f, 0.5019607843137255f}}, // purple
+ {{349.5238095238096f / 60.0f, 1.00f, 0.876470588235294f},
+ {1.0f, 0.7529411764705882f, 0.796078431372549f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_h, input_s, input_l] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ SkColor4f color = HSLToSkColor4f(input_h, input_s, input_l, 1.0f);
+ EXPECT_NEAR(color.fR, expected_r, 0.01f)
+ << input_h << ' ' << input_s << ' ' << input_l << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fG, expected_g, 0.01f)
+ << input_h << ' ' << input_s << ' ' << input_l << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fB, expected_b, 0.01f)
+ << input_h << ' ' << input_s << ' ' << input_l << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ }
+}
+
+TEST(ColorConversions, HWBToSkColor4f) {
+ // Color conversions obtained from
+ // https://colorjs.io/apps/convert/?color=purple&precision=4
+ ColorTest colors_tests[] = {
+ {{0.0f, 0.0f, 1.0f}, {0.0f, 0.0f, 0.0f}}, // black
+ {{0.0f, 1.f, 0.f}, {1.0f, 1.0f, 1.0f}}, // white
+ {{0.0f, 0.5f, 0.5f}, {0.5, 0.5, 0.5}}, // grey
+ {{5.0f, 0.5f, 0.5f}, {0.5, 0.5, 0.5}}, // grey
+ {{120.0f / 60.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f}}, // lime
+ {{0.0f, 0.1647058823529411f, 0.35294117647058826f},
+ {0.6470588235294118f, 0.16470588235294117f,
+ 0.16470588235294117f}}, // brown
+ {{300.0f / 60.0f, 0.0f, 0.4980392156862745f},
+ {0.5019607843137255f, 0.0f, 0.5019607843137255f}}, // purple
+ {{349.5238095238096f / 60.0f, 0.7529411764705883f, 0.0f},
+ {1.0f, 0.7529411764705882f, 0.796078431372549f}}}; // pink
+
+ for (auto& color_pair : colors_tests) {
+ auto [input_h, input_w, input_b] = color_pair.input;
+ auto [expected_r, expected_g, expected_b] = color_pair.expected;
+ SkColor4f color = HWBToSkColor4f(input_h, input_w, input_b, 1.0f);
+ EXPECT_NEAR(color.fR, expected_r, 0.01f)
+ << input_h << ' ' << input_w << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fG, expected_g, 0.01f)
+ << input_h << ' ' << input_w << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ EXPECT_NEAR(color.fB, expected_b, 0.01f)
+ << input_h << ' ' << input_w << ' ' << input_b << " to " << expected_r
+ << ' ' << expected_g << ' ' << expected_b << " produced " << color.fR
+ << ' ' << color.fG << ' ' << color.fB;
+ }
+}
+
+} // namespace gfx
\ No newline at end of file
diff --git a/ui/gfx/color_palette.h b/ui/gfx/color_palette.h
index ebf2cde..8ba3629 100644
--- a/ui/gfx/color_palette.h
+++ b/ui/gfx/color_palette.h
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -26,9 +26,6 @@
constexpr SkColor kGoogleBlue800 = SkColorSetRGB(0x18, 0x5A, 0xBC);
constexpr SkColor kGoogleBlue900 = SkColorSetRGB(0x17, 0x4E, 0xA6);
-constexpr SkColor kGoogleBlueDark400 = SkColorSetRGB(0x6B, 0xA5, 0xED);
-constexpr SkColor kGoogleBlueDark600 = SkColorSetRGB(0x25, 0x81, 0xDF);
-
constexpr SkColor kGoogleRed050 = SkColorSetRGB(0xFC, 0xE8, 0xE6);
constexpr SkColor kGoogleRed100 = SkColorSetRGB(0xFA, 0xD2, 0xCF);
constexpr SkColor kGoogleRed200 = SkColorSetRGB(0xF6, 0xAE, 0xA9);
@@ -40,10 +37,6 @@
constexpr SkColor kGoogleRed800 = SkColorSetRGB(0xB3, 0x14, 0x12);
constexpr SkColor kGoogleRed900 = SkColorSetRGB(0xA5, 0x0E, 0x0E);
-constexpr SkColor kGoogleRedDark500 = SkColorSetRGB(0xE6, 0x6A, 0x5E);
-constexpr SkColor kGoogleRedDark600 = SkColorSetRGB(0xD3, 0x3B, 0x30);
-constexpr SkColor kGoogleRedDark800 = SkColorSetRGB(0xB4, 0x1B, 0x1A);
-
constexpr SkColor kGoogleGreen050 = SkColorSetRGB(0xE6, 0xF4, 0xEA);
constexpr SkColor kGoogleGreen100 = SkColorSetRGB(0xCE, 0xEA, 0xD6);
constexpr SkColor kGoogleGreen200 = SkColorSetRGB(0xA8, 0xDA, 0xB5);
@@ -55,9 +48,6 @@
constexpr SkColor kGoogleGreen800 = SkColorSetRGB(0x13, 0x73, 0x33);
constexpr SkColor kGoogleGreen900 = SkColorSetRGB(0x0D, 0x65, 0x2D);
-constexpr SkColor kGoogleGreenDark500 = SkColorSetRGB(0x41, 0xAF, 0x6A);
-constexpr SkColor kGoogleGreenDark600 = SkColorSetRGB(0x28, 0x99, 0x4F);
-
constexpr SkColor kGoogleYellow050 = SkColorSetRGB(0xFE, 0xF7, 0xE0);
constexpr SkColor kGoogleYellow100 = SkColorSetRGB(0xFE, 0xEF, 0xC3);
constexpr SkColor kGoogleYellow200 = SkColorSetRGB(0xFD, 0xE2, 0x93);
@@ -124,6 +114,28 @@
constexpr SkColor kGoogleCyan800 = SkColorSetRGB(0x09, 0x85, 0x91);
constexpr SkColor kGoogleCyan900 = SkColorSetRGB(0x00, 0x7B, 0x83);
+constexpr SkColor kGoogleMagenta050 = SkColorSetRGB(0xF6, 0xE9, 0xF8);
+constexpr SkColor kGoogleMagenta100 = SkColorSetRGB(0xFA, 0xCB, 0xFF);
+constexpr SkColor kGoogleMagenta200 = SkColorSetRGB(0xF4, 0xB5, 0xFB);
+constexpr SkColor kGoogleMagenta300 = SkColorSetRGB(0xF8, 0x82, 0xFF);
+constexpr SkColor kGoogleMagenta400 = SkColorSetRGB(0xEE, 0x5F, 0xFA);
+constexpr SkColor kGoogleMagenta500 = SkColorSetRGB(0xDA, 0x36, 0xE8);
+constexpr SkColor kGoogleMagenta600 = SkColorSetRGB(0xC6, 0x1A, 0xD9);
+constexpr SkColor kGoogleMagenta700 = SkColorSetRGB(0xAA, 0x00, 0xB8);
+constexpr SkColor kGoogleMagenta800 = SkColorSetRGB(0x8A, 0x0E, 0x9E);
+constexpr SkColor kGoogleMagenta900 = SkColorSetRGB(0x68, 0x09, 0x8A);
+
+constexpr SkColor kGoogleElectric050 = SkColorSetRGB(0xE7, 0xFD, 0xFD);
+constexpr SkColor kGoogleElectric100 = SkColorSetRGB(0xBA, 0xFF, 0xFF);
+constexpr SkColor kGoogleElectric200 = SkColorSetRGB(0x80, 0xF9, 0xF9);
+constexpr SkColor kGoogleElectric300 = SkColorSetRGB(0x5E, 0xF1, 0xF2);
+constexpr SkColor kGoogleElectric400 = SkColorSetRGB(0x30, 0xE2, 0xEA);
+constexpr SkColor kGoogleElectric500 = SkColorSetRGB(0x2B, 0xDD, 0xE5);
+constexpr SkColor kGoogleElectric600 = SkColorSetRGB(0x03, 0xB6, 0xBE);
+constexpr SkColor kGoogleElectric700 = SkColorSetRGB(0x00, 0x90, 0x99);
+constexpr SkColor kGoogleElectric800 = SkColorSetRGB(0x00, 0x72, 0x82);
+constexpr SkColor kGoogleElectric900 = SkColorSetRGB(0x00, 0x5B, 0x70);
+
// The following are the values that correspond to the above kGoogleGreyXXX
// values, which are the opaque colors created from the following alpha values
// applied to kGoogleGrey900 on a white background.
@@ -139,12 +151,6 @@
constexpr SkAlpha kGoogleGreyAlpha700 = 0xB5; // 71%
constexpr SkAlpha kGoogleGreyAlpha800 = 0xDB; // 86%
-// kChromeIconGrey is subject to change in the future, kGoogleGrey700 is set in
-// stone. If you're semantically looking for "the icon color Chrome uses" then
-// use kChromeIconGrey, if you're looking for GG700 grey specifically, use the
-// Google-grey constant directly.
-constexpr SkColor kChromeIconGrey = kGoogleGrey700;
-
// An alpha value for designating a control's disabled state. In specs this is
// sometimes listed as 0.38a.
constexpr SkAlpha kDisabledControlAlpha = 0x61;
diff --git a/ui/gfx/color_space.cc b/ui/gfx/color_space.cc
index 02a4fee..202faa8 100644
--- a/ui/gfx/color_space.cc
+++ b/ui/gfx/color_space.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -12,11 +12,15 @@
#include "base/atomic_sequence_num.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/notreached.h"
#include "base/synchronization/lock.h"
+#include "skia/ext/skcolorspace_primaries.h"
+#include "skia/ext/skcolorspace_trfn.h"
#include "third_party/skia/include/core/SkColorSpace.h"
#include "third_party/skia/include/core/SkData.h"
-#include "third_party/skia/include/core/SkICC.h"
#include "third_party/skia/include/core/SkImageInfo.h"
+#include "third_party/skia/include/core/SkM44.h"
+#include "third_party/skia/modules/skcms/skcms.h"
#include "ui/gfx/display_color_spaces.h"
#include "ui/gfx/icc_profile.h"
#include "ui/gfx/skia_color_space_util.h"
@@ -25,8 +29,12 @@
namespace {
-static bool IsAlmostZero(float value) {
- return std::abs(value) < std::numeric_limits<float>::epsilon();
+// Videos that are from a 10 or 12 bit source, but are stored in a 16-bit
+// format (e.g, PIXEL_FORMAT_P016LE) will report having 16 bits per pixel.
+// Assume they have 10 bits per pixel.
+// https://crbug.com/1381100
+int BitDepthWithWorkaroundApplied(int bit_depth) {
+ return bit_depth == 16 ? 10 : bit_depth;
}
static bool FloatsEqualWithinTolerance(const float* a,
@@ -67,31 +75,18 @@
if (sdr_white_level == 0.f)
sdr_white_level = ColorSpace::kDefaultSDRWhiteLevel;
- // The reference white level for HLG is 100 nits. We want to setup the
- // returned transfer function such that output values are scaled by the white
- // level; Skia uses the |f| transfer function parameter for this.
+ // The kHLG constant will evaluate to values in the range [0, 12].
skcms_TransferFunction fn = SkNamedTransferFn::kHLG;
- fn.f = ColorSpace::kDefaultSDRWhiteLevel / sdr_white_level - 1;
+
+ // The value of k is equal to kHLG evaluated at 0.75 (3.77) , divided by kHLG
+ // evaluated at 1 (12), multiplied by 203 nits. This value is selected such
+ // that a signal of 0.75 will map to the same value that a PQ signal for 203
+ // nits will map to.
+ constexpr float k = 63.84549817071231f;
+ fn.f = k / sdr_white_level - 1;
return fn;
}
-float GetSDRWhiteLevelFromPQSkTransferFunction(
- const skcms_TransferFunction& fn) {
- DCHECK_EQ(fn.g, SkNamedTransferFn::kPQ.g);
- const double ws_a = static_cast<double>(fn.a) / SkNamedTransferFn::kPQ.a;
- const double w_a = pow(ws_a, fn.f);
- const double sdr_white_level_a = 10000.0f / w_a;
- return sdr_white_level_a;
-}
-
-float GetSDRWhiteLevelFromHLGSkTransferFunction(
- const skcms_TransferFunction& fn) {
- DCHECK_EQ(fn.g, SkNamedTransferFn::kHLG.g);
- if (fn.f == 0)
- return ColorSpace::kDefaultSDRWhiteLevel;
- return 1.0f / ((fn.f + 1) / ColorSpace::kDefaultSDRWhiteLevel);
-}
-
bool PrimaryIdContainsSRGB(ColorSpace::PrimaryID id) {
DCHECK(id != ColorSpace::PrimaryID::INVALID &&
id != ColorSpace::PrimaryID::CUSTOM);
@@ -101,7 +96,7 @@
case ColorSpace::PrimaryID::BT2020:
case ColorSpace::PrimaryID::SMPTEST428_1:
case ColorSpace::PrimaryID::SMPTEST431_2:
- case ColorSpace::PrimaryID::SMPTEST432_1:
+ case ColorSpace::PrimaryID::P3:
case ColorSpace::PrimaryID::XYZ_D50:
case ColorSpace::PrimaryID::ADOBE_RGB:
case ColorSpace::PrimaryID::WIDE_GAMUT_COLOR_SPIN:
@@ -130,25 +125,24 @@
DCHECK_EQ(PrimaryID::CUSTOM, primaries_);
SetCustomPrimaries(*custom_primary_matrix);
}
- if (custom_transfer_fn)
+ if (custom_transfer_fn) {
SetCustomTransferFunction(*custom_transfer_fn);
+ }
}
-ColorSpace::ColorSpace(const SkColorSpace& sk_color_space)
+ColorSpace::ColorSpace(const SkColorSpace& sk_color_space, bool is_hdr)
: ColorSpace(PrimaryID::INVALID,
TransferID::INVALID,
MatrixID::RGB,
RangeID::FULL) {
skcms_TransferFunction fn;
if (sk_color_space.isNumericalTransferFn(&fn)) {
- transfer_ = TransferID::CUSTOM;
+ transfer_ = is_hdr ? TransferID::CUSTOM_HDR : TransferID::CUSTOM;
SetCustomTransferFunction(fn);
} else if (skcms_TransferFunction_isHLGish(&fn)) {
- transfer_ = TransferID::ARIB_STD_B67;
- transfer_params_[0] = GetSDRWhiteLevelFromHLGSkTransferFunction(fn);
+ transfer_ = TransferID::HLG;
} else if (skcms_TransferFunction_isPQish(&fn)) {
- transfer_ = TransferID::SMPTEST2084;
- transfer_params_[0] = GetSDRWhiteLevelFromPQSkTransferFunction(fn);
+ transfer_ = TransferID::PQ;
} else {
// Construct an invalid result: Unable to extract necessary parameters
return;
@@ -168,26 +162,10 @@
}
// static
-ColorSpace ColorSpace::CreateSCRGBLinear(float sdr_white_level) {
- skcms_TransferFunction fn = {0};
- fn.g = 1.0f;
- fn.a = kDefaultScrgbLinearSdrWhiteLevel / sdr_white_level;
- return ColorSpace(PrimaryID::BT709, TransferID::CUSTOM_HDR, MatrixID::RGB,
- RangeID::FULL, nullptr, &fn);
-}
-
-// static
-ColorSpace ColorSpace::CreateHDR10(float sdr_white_level) {
- ColorSpace result(PrimaryID::BT2020, TransferID::SMPTEST2084, MatrixID::RGB,
- RangeID::FULL);
- result.transfer_params_[0] = sdr_white_level;
- return result;
-}
-
-// static
-ColorSpace ColorSpace::CreateHLG() {
- return ColorSpace(PrimaryID::BT2020, TransferID::ARIB_STD_B67, MatrixID::RGB,
- RangeID::FULL);
+ColorSpace ColorSpace::CreateExtendedSRGB10Bit() {
+ return ColorSpace(PrimaryID::P3, TransferID::CUSTOM_HDR, MatrixID::RGB,
+ RangeID::FULL, nullptr,
+ &SkNamedTransferFnExt::kSRGBExtended1023Over510);
}
// static
@@ -239,7 +217,7 @@
PrimaryID::BT2020,
PrimaryID::SMPTEST428_1,
PrimaryID::SMPTEST431_2,
- PrimaryID::SMPTEST432_1,
+ PrimaryID::P3,
PrimaryID::XYZ_D50,
PrimaryID::ADOBE_RGB,
PrimaryID::APPLE_GENERIC_RGB,
@@ -262,27 +240,47 @@
void ColorSpace::SetCustomTransferFunction(const skcms_TransferFunction& fn) {
DCHECK(transfer_ == TransferID::CUSTOM ||
transfer_ == TransferID::CUSTOM_HDR);
- // These are all TransferIDs that will return a transfer function from
- // GetTransferFunction. When multiple ids map to the same function, this list
- // prioritizes the most common name (eg IEC61966_2_1). This applies only to
- // SDR transfer functions.
+
+ auto check_transfer_fn = [this, &fn](TransferID id) {
+ skcms_TransferFunction id_fn;
+ GetTransferFunction(id, &id_fn);
+ if (!FloatsEqualWithinTolerance(&fn.g, &id_fn.g, 7, 0.001f)) {
+ return false;
+ }
+ transfer_ = id;
+ return true;
+ };
+
if (transfer_ == TransferID::CUSTOM) {
+ // These are all TransferIDs that will return a transfer function from
+ // GetTransferFunction. When multiple ids map to the same function, this
+ // list prioritizes the most common name (eg SRGB).
const TransferID kIDsToCheck[] = {
- TransferID::IEC61966_2_1, TransferID::LINEAR,
+ TransferID::SRGB, TransferID::LINEAR,
TransferID::GAMMA18, TransferID::GAMMA22,
TransferID::GAMMA24, TransferID::GAMMA28,
TransferID::SMPTE240M, TransferID::BT709_APPLE,
TransferID::SMPTEST428_1,
};
for (TransferID id : kIDsToCheck) {
- skcms_TransferFunction id_fn;
- GetTransferFunction(id, &id_fn);
- if (FloatsEqualWithinTolerance(&fn.g, &id_fn.g, 7, 0.001f)) {
- transfer_ = id;
+ if (check_transfer_fn(id))
+ return;
+ }
+ }
+
+ if (transfer_ == TransferID::CUSTOM_HDR) {
+ // This list is the same as above, but for HDR TransferIDs.
+ const TransferID kIDsToCheckHDR[] = {
+ TransferID::SRGB_HDR,
+ TransferID::LINEAR_HDR,
+ };
+ for (TransferID id : kIDsToCheckHDR) {
+ if (check_transfer_fn(id)) {
return;
}
}
}
+
transfer_params_[0] = fn.a;
transfer_params_[1] = fn.b;
transfer_params_[2] = fn.c;
@@ -301,9 +299,6 @@
return 7;
case TransferID::PIECEWISE_HDR:
return 2;
- case TransferID::SMPTEST2084:
- case TransferID::ARIB_STD_B67:
- return 1;
default:
return 0;
}
@@ -331,14 +326,13 @@
bool ColorSpace::IsWide() const {
// These HDR transfer functions are always wide
- if (transfer_ == TransferID::IEC61966_2_1_HDR ||
+ if (transfer_ == TransferID::SRGB_HDR ||
transfer_ == TransferID::LINEAR_HDR ||
transfer_ == TransferID::CUSTOM_HDR)
return true;
if (primaries_ == PrimaryID::BT2020 ||
- primaries_ == PrimaryID::SMPTEST431_2 ||
- primaries_ == PrimaryID::SMPTEST432_1 ||
+ primaries_ == PrimaryID::SMPTEST431_2 || primaries_ == PrimaryID::P3 ||
primaries_ == PrimaryID::ADOBE_RGB ||
primaries_ == PrimaryID::WIDE_GAMUT_COLOR_SPIN ||
// TODO(cblume/ccameron): Compute if the custom primaries actually are
@@ -350,19 +344,41 @@
}
bool ColorSpace::IsHDR() const {
- return transfer_ == TransferID::SMPTEST2084 ||
- transfer_ == TransferID::ARIB_STD_B67 ||
+ return transfer_ == TransferID::PQ || transfer_ == TransferID::HLG ||
transfer_ == TransferID::LINEAR_HDR ||
- transfer_ == TransferID::IEC61966_2_1_HDR ||
+ transfer_ == TransferID::SRGB_HDR ||
transfer_ == TransferID::CUSTOM_HDR ||
- transfer_ == TransferID::PIECEWISE_HDR;
+ transfer_ == TransferID::PIECEWISE_HDR ||
+ transfer_ == TransferID::SCRGB_LINEAR_80_NITS;
+}
+
+bool ColorSpace::IsToneMappedByDefault() const {
+ switch (transfer_) {
+ case TransferID::PQ:
+ case TransferID::HLG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool ColorSpace::IsAffectedBySDRWhiteLevel() const {
+ switch (transfer_) {
+ case TransferID::PQ:
+ case TransferID::HLG:
+ case TransferID::SCRGB_LINEAR_80_NITS:
+ return true;
+ default:
+ return false;
+ }
}
bool ColorSpace::FullRangeEncodedValues() const {
return transfer_ == TransferID::LINEAR_HDR ||
- transfer_ == TransferID::IEC61966_2_1_HDR ||
+ transfer_ == TransferID::SRGB_HDR ||
transfer_ == TransferID::CUSTOM_HDR ||
transfer_ == TransferID::PIECEWISE_HDR ||
+ transfer_ == TransferID::SCRGB_LINEAR_80_NITS ||
transfer_ == TransferID::BT1361_ECG ||
transfer_ == TransferID::IEC61966_2_4;
}
@@ -451,28 +467,13 @@
PRINT_ENUM_CASE(PrimaryID, BT2020)
PRINT_ENUM_CASE(PrimaryID, SMPTEST428_1)
PRINT_ENUM_CASE(PrimaryID, SMPTEST431_2)
- PRINT_ENUM_CASE(PrimaryID, SMPTEST432_1)
+ PRINT_ENUM_CASE(PrimaryID, P3)
PRINT_ENUM_CASE(PrimaryID, XYZ_D50)
PRINT_ENUM_CASE(PrimaryID, ADOBE_RGB)
PRINT_ENUM_CASE(PrimaryID, APPLE_GENERIC_RGB)
PRINT_ENUM_CASE(PrimaryID, WIDE_GAMUT_COLOR_SPIN)
case PrimaryID::CUSTOM:
- // |custom_primary_matrix_| is in row-major order.
- const float sum_R = custom_primary_matrix_[0] +
- custom_primary_matrix_[3] + custom_primary_matrix_[6];
- const float sum_G = custom_primary_matrix_[1] +
- custom_primary_matrix_[4] + custom_primary_matrix_[7];
- const float sum_B = custom_primary_matrix_[2] +
- custom_primary_matrix_[5] + custom_primary_matrix_[8];
- if (IsAlmostZero(sum_R) || IsAlmostZero(sum_G) || IsAlmostZero(sum_B))
- break;
-
- ss << "{primaries_d50_referred: [[" << (custom_primary_matrix_[0] / sum_R)
- << ", " << (custom_primary_matrix_[3] / sum_R) << "], "
- << " [" << (custom_primary_matrix_[1] / sum_G) << ", "
- << (custom_primary_matrix_[4] / sum_G) << "], "
- << " [" << (custom_primary_matrix_[2] / sum_B) << ", "
- << (custom_primary_matrix_[5] / sum_B) << "]]";
+ ss << skia::SkColorSpacePrimariesToString(GetPrimaries());
break;
}
ss << ", transfer:";
@@ -491,13 +492,13 @@
PRINT_ENUM_CASE(TransferID, LOG_SQRT)
PRINT_ENUM_CASE(TransferID, IEC61966_2_4)
PRINT_ENUM_CASE(TransferID, BT1361_ECG)
- PRINT_ENUM_CASE(TransferID, IEC61966_2_1)
+ PRINT_ENUM_CASE(TransferID, SRGB)
PRINT_ENUM_CASE(TransferID, BT2020_10)
PRINT_ENUM_CASE(TransferID, BT2020_12)
PRINT_ENUM_CASE(TransferID, SMPTEST428_1)
- PRINT_ENUM_CASE(TransferID, IEC61966_2_1_HDR)
+ PRINT_ENUM_CASE(TransferID, SRGB_HDR)
PRINT_ENUM_CASE(TransferID, LINEAR_HDR)
- case TransferID::ARIB_STD_B67:
+ case TransferID::HLG:
ss << "HLG (SDR white point ";
if (transfer_params_[0] == 0.f)
ss << "default " << kDefaultSDRWhiteLevel;
@@ -505,7 +506,7 @@
ss << transfer_params_[0];
ss << " nits)";
break;
- case TransferID::SMPTEST2084:
+ case TransferID::PQ:
ss << "PQ (SDR white point ";
if (transfer_params_[0] == 0.f)
ss << "default " << kDefaultSDRWhiteLevel;
@@ -525,8 +526,7 @@
GetTransferFunction(&fn);
if (fn.g == 1.0f && fn.a > 0.0f && fn.b == 0.0f && fn.c == 0.0f &&
fn.d == 0.0f && fn.e == 0.0f && fn.f == 0.0f) {
- ss << "LINEAR_HDR (slope " << fn.a << ", SDR white point "
- << kDefaultScrgbLinearSdrWhiteLevel / fn.a << " nits)";
+ ss << "LINEAR_HDR (slope " << fn.a << ")";
break;
}
ss << fn.c << "*x + " << fn.f << " if |x| < " << fn.d << " else sign(x)*("
@@ -540,6 +540,9 @@
<< transfer_params_[1] << " at 1";
break;
}
+ case TransferID::SCRGB_LINEAR_80_NITS:
+ ss << "scRGB linear (80 nit white)";
+ break;
}
ss << ", matrix:";
switch (matrix_) {
@@ -608,12 +611,13 @@
bool ColorSpace::IsSuitableForBlending() const {
switch (transfer_) {
- case TransferID::SMPTEST2084:
+ case TransferID::PQ:
// PQ is not an acceptable space to do blending in -- blending 0 and 1
// evenly will get a result of sRGB 0.259 (instead of 0.5).
return false;
- case TransferID::ARIB_STD_B67:
+ case TransferID::HLG:
case TransferID::LINEAR_HDR:
+ case TransferID::SCRGB_LINEAR_80_NITS:
// If the color space is nearly-linear, then it is not suitable for
// blending -- blending 0 and 1 evenly will get a result of sRGB 0.735
// (instead of 0.5).
@@ -645,60 +649,38 @@
return result;
}
-ColorSpace ColorSpace::GetWithSDRWhiteLevel(float sdr_white_level) const {
- ColorSpace result = *this;
- if (transfer_ == TransferID::SMPTEST2084 ||
- transfer_ == TransferID::ARIB_STD_B67) {
- result.transfer_params_[0] = sdr_white_level;
- } else if (transfer_ == TransferID::LINEAR_HDR) {
- result.transfer_ = TransferID::CUSTOM_HDR;
- skcms_TransferFunction fn = {0};
- fn.g = 1.f;
- fn.a = kDefaultScrgbLinearSdrWhiteLevel / sdr_white_level;
- result.SetCustomTransferFunction(fn);
- }
- return result;
-}
-
-sk_sp<SkColorSpace> ColorSpace::ToSkColorSpace() const {
- // Unspecified color spaces correspond to the null SkColorSpace.
- if (!IsValid())
+sk_sp<SkColorSpace> ColorSpace::ToSkColorSpace(
+ absl::optional<float> sdr_white_level) const {
+ // Handle only valid, full-range RGB spaces.
+ if (!IsValid() || matrix_ != MatrixID::RGB || range_ != RangeID::FULL)
return nullptr;
- // Handle only full-range RGB spaces.
- if (matrix_ != MatrixID::RGB) {
- DLOG(ERROR) << "Not creating non-RGB SkColorSpace";
- return nullptr;
- }
- if (range_ != RangeID::FULL) {
- DLOG(ERROR) << "Not creating non-full-range SkColorSpace";
- return nullptr;
- }
-
// Use the named SRGB and linear-SRGB instead of the generic constructors.
if (primaries_ == PrimaryID::BT709) {
- if (transfer_ == TransferID::IEC61966_2_1)
+ if (transfer_ == TransferID::SRGB)
return SkColorSpace::MakeSRGB();
if (transfer_ == TransferID::LINEAR || transfer_ == TransferID::LINEAR_HDR)
return SkColorSpace::MakeSRGBLinear();
}
- skcms_TransferFunction transfer_fn = SkNamedTransferFn::kSRGB;
+ skcms_TransferFunction transfer_fn = SkNamedTransferFnExt::kSRGB;
switch (transfer_) {
- case TransferID::IEC61966_2_1:
+ case TransferID::SRGB:
break;
case TransferID::LINEAR:
case TransferID::LINEAR_HDR:
transfer_fn = SkNamedTransferFn::kLinear;
break;
- case TransferID::ARIB_STD_B67:
- transfer_fn = GetHLGSkTransferFunction(transfer_params_[0]);
+ case TransferID::HLG:
+ transfer_fn = GetHLGSkTransferFunction(
+ sdr_white_level.value_or(kDefaultSDRWhiteLevel));
break;
- case TransferID::SMPTEST2084:
- transfer_fn = GetPQSkTransferFunction(transfer_params_[0]);
+ case TransferID::PQ:
+ transfer_fn = GetPQSkTransferFunction(
+ sdr_white_level.value_or(kDefaultSDRWhiteLevel));
break;
default:
- if (!GetTransferFunction(&transfer_fn)) {
+ if (!GetTransferFunction(&transfer_fn, sdr_white_level)) {
DLOG(ERROR) << "Failed to get transfer function for SkColorSpace";
return nullptr;
}
@@ -711,7 +693,7 @@
case PrimaryID::ADOBE_RGB:
gamut = SkNamedGamut::kAdobeRGB;
break;
- case PrimaryID::SMPTEST432_1:
+ case PrimaryID::P3:
gamut = SkNamedGamut::kDisplayP3;
break;
case PrimaryID::BT2020:
@@ -721,7 +703,6 @@
GetPrimaryMatrix(&gamut);
break;
}
-
sk_sp<SkColorSpace> sk_color_space =
SkColorSpace::MakeRGB(transfer_fn, gamut);
if (!sk_color_space)
@@ -751,8 +732,23 @@
}
bool ColorSpace::HasExtendedSkTransferFn() const {
- return transfer_ == TransferID::LINEAR_HDR ||
- transfer_ == TransferID::IEC61966_2_1_HDR;
+ return matrix_ == MatrixID::RGB;
+}
+
+bool ColorSpace::IsTransferFunctionEqualTo(
+ const skcms_TransferFunction& fn) const {
+ if (transfer_ == TransferID::PQ)
+ return skcms_TransferFunction_isPQish(&fn);
+ if (transfer_ == TransferID::HLG)
+ return skcms_TransferFunction_isHLGish(&fn);
+ if (!skcms_TransferFunction_isSRGBish(&fn))
+ return false;
+ skcms_TransferFunction transfer_fn;
+ GetTransferFunction(&transfer_fn);
+ return fn.a == transfer_fn.a && fn.b == transfer_fn.b &&
+ fn.c == transfer_fn.c && fn.d == transfer_fn.d &&
+ fn.e == transfer_fn.e && fn.f == transfer_fn.f &&
+ fn.g == transfer_fn.g;
}
bool ColorSpace::Contains(const ColorSpace& other) const {
@@ -789,162 +785,82 @@
}
// static
-void ColorSpace::GetPrimaryMatrix(PrimaryID primary_id,
- skcms_Matrix3x3* to_XYZD50) {
- SkColorSpacePrimaries primaries = {0};
+SkColorSpacePrimaries ColorSpace::GetColorSpacePrimaries(
+ PrimaryID primary_id,
+ const skcms_Matrix3x3* custom_primary_matrix = nullptr) {
+ SkColorSpacePrimaries primaries = SkNamedPrimariesExt::kInvalid;
+
+ if (custom_primary_matrix && primary_id == PrimaryID::CUSTOM)
+ return skia::GetD65PrimariesFromToXYZD50Matrix(*custom_primary_matrix);
+
switch (primary_id) {
case ColorSpace::PrimaryID::CUSTOM:
case ColorSpace::PrimaryID::INVALID:
- *to_XYZD50 = SkNamedGamut::kXYZ; // Identity
- return;
+ break;
case ColorSpace::PrimaryID::BT709:
// BT709 is our default case. Put it after the switch just
// in case we somehow get an id which is not listed in the switch.
// (We don't want to use "default", because we want the compiler
// to tell us if we forgot some enum values.)
- primaries.fRX = 0.640f;
- primaries.fRY = 0.330f;
- primaries.fGX = 0.300f;
- primaries.fGY = 0.600f;
- primaries.fBX = 0.150f;
- primaries.fBY = 0.060f;
- primaries.fWX = 0.3127f;
- primaries.fWY = 0.3290f;
- break;
+ return SkNamedPrimariesExt::kRec709;
case ColorSpace::PrimaryID::BT470M:
- primaries.fRX = 0.67f;
- primaries.fRY = 0.33f;
- primaries.fGX = 0.21f;
- primaries.fGY = 0.71f;
- primaries.fBX = 0.14f;
- primaries.fBY = 0.08f;
- primaries.fWX = 0.31f;
- primaries.fWY = 0.316f;
- break;
+ return SkNamedPrimariesExt::kRec470SystemM;
case ColorSpace::PrimaryID::BT470BG:
- primaries.fRX = 0.64f;
- primaries.fRY = 0.33f;
- primaries.fGX = 0.29f;
- primaries.fGY = 0.60f;
- primaries.fBX = 0.15f;
- primaries.fBY = 0.06f;
- primaries.fWX = 0.3127f;
- primaries.fWY = 0.3290f;
- break;
+ return SkNamedPrimariesExt::kRec470SystemBG;
case ColorSpace::PrimaryID::SMPTE170M:
+ return SkNamedPrimariesExt::kRec601;
+
case ColorSpace::PrimaryID::SMPTE240M:
- primaries.fRX = 0.630f;
- primaries.fRY = 0.340f;
- primaries.fGX = 0.310f;
- primaries.fGY = 0.595f;
- primaries.fBX = 0.155f;
- primaries.fBY = 0.070f;
- primaries.fWX = 0.3127f;
- primaries.fWY = 0.3290f;
- break;
+ return SkNamedPrimariesExt::kSMPTE_ST_240;
case ColorSpace::PrimaryID::APPLE_GENERIC_RGB:
- primaries.fRX = 0.63002f;
- primaries.fRY = 0.34000f;
- primaries.fGX = 0.29505f;
- primaries.fGY = 0.60498f;
- primaries.fBX = 0.15501f;
- primaries.fBY = 0.07701f;
- primaries.fWX = 0.3127f;
- primaries.fWY = 0.3290f;
- break;
+ return SkNamedPrimariesExt::kAppleGenericRGB;
case ColorSpace::PrimaryID::WIDE_GAMUT_COLOR_SPIN:
- primaries.fRX = 0.01f;
- primaries.fRY = 0.98f;
- primaries.fGX = 0.01f;
- primaries.fGY = 0.01f;
- primaries.fBX = 0.98f;
- primaries.fBY = 0.01f;
- primaries.fWX = 0.3127f;
- primaries.fWY = 0.3290f;
- break;
+ return SkNamedPrimariesExt::kWideGamutColorSpin;
case ColorSpace::PrimaryID::FILM:
- primaries.fRX = 0.681f;
- primaries.fRY = 0.319f;
- primaries.fGX = 0.243f;
- primaries.fGY = 0.692f;
- primaries.fBX = 0.145f;
- primaries.fBY = 0.049f;
- primaries.fWX = 0.310f;
- primaries.fWY = 0.136f;
- break;
+ return SkNamedPrimariesExt::kGenericFilm;
case ColorSpace::PrimaryID::BT2020:
- primaries.fRX = 0.708f;
- primaries.fRY = 0.292f;
- primaries.fGX = 0.170f;
- primaries.fGY = 0.797f;
- primaries.fBX = 0.131f;
- primaries.fBY = 0.046f;
- primaries.fWX = 0.3127f;
- primaries.fWY = 0.3290f;
- break;
+ return SkNamedPrimariesExt::kRec2020;
case ColorSpace::PrimaryID::SMPTEST428_1:
- primaries.fRX = 1.0f;
- primaries.fRY = 0.0f;
- primaries.fGX = 0.0f;
- primaries.fGY = 1.0f;
- primaries.fBX = 0.0f;
- primaries.fBY = 0.0f;
- primaries.fWX = 1.0f / 3.0f;
- primaries.fWY = 1.0f / 3.0f;
- break;
+ return SkNamedPrimariesExt::kSMPTE_ST_428_1;
case ColorSpace::PrimaryID::SMPTEST431_2:
- primaries.fRX = 0.680f;
- primaries.fRY = 0.320f;
- primaries.fGX = 0.265f;
- primaries.fGY = 0.690f;
- primaries.fBX = 0.150f;
- primaries.fBY = 0.060f;
- primaries.fWX = 0.314f;
- primaries.fWY = 0.351f;
- break;
+ return SkNamedPrimariesExt::kSMPTE_RP_431_2;
- case ColorSpace::PrimaryID::SMPTEST432_1:
- primaries.fRX = 0.680f;
- primaries.fRY = 0.320f;
- primaries.fGX = 0.265f;
- primaries.fGY = 0.690f;
- primaries.fBX = 0.150f;
- primaries.fBY = 0.060f;
- primaries.fWX = 0.3127f;
- primaries.fWY = 0.3290f;
- break;
+ case ColorSpace::PrimaryID::P3:
+ return SkNamedPrimariesExt::kP3;
case ColorSpace::PrimaryID::XYZ_D50:
- primaries.fRX = 1.0f;
- primaries.fRY = 0.0f;
- primaries.fGX = 0.0f;
- primaries.fGY = 1.0f;
- primaries.fBX = 0.0f;
- primaries.fBY = 0.0f;
- primaries.fWX = 0.34567f;
- primaries.fWY = 0.35850f;
- break;
+ return SkNamedPrimariesExt::kXYZD50;
case ColorSpace::PrimaryID::ADOBE_RGB:
- primaries.fRX = 0.6400f;
- primaries.fRY = 0.3300f;
- primaries.fGX = 0.2100f;
- primaries.fGY = 0.7100f;
- primaries.fBX = 0.1500f;
- primaries.fBY = 0.0600f;
- primaries.fWX = 0.3127f;
- primaries.fWY = 0.3290f;
- break;
+ return SkNamedPrimariesExt::kA98RGB;
+ }
+ return primaries;
+}
+
+SkColorSpacePrimaries ColorSpace::GetPrimaries() const {
+ skcms_Matrix3x3 matrix;
+ memcpy(&matrix, custom_primary_matrix_, 9 * sizeof(float));
+ return GetColorSpacePrimaries(primaries_, &matrix);
+}
+
+// static
+void ColorSpace::GetPrimaryMatrix(PrimaryID primary_id,
+ skcms_Matrix3x3* to_XYZD50) {
+ SkColorSpacePrimaries primaries = GetColorSpacePrimaries(primary_id);
+
+ if (primary_id == PrimaryID::CUSTOM || primary_id == PrimaryID::INVALID) {
+ *to_XYZD50 = SkNamedGamut::kXYZ; // Identity
+ return;
}
primaries.toXYZD50(to_XYZD50);
}
@@ -957,10 +873,10 @@
}
}
-void ColorSpace::GetPrimaryMatrix(skia::Matrix44* to_XYZD50) const {
+SkM44 ColorSpace::GetPrimaryMatrix() const {
skcms_Matrix3x3 toXYZ_3x3;
GetPrimaryMatrix(&toXYZ_3x3);
- to_XYZD50->set3x3RowMajorf(&toXYZ_3x3.vals[0][0]);
+ return SkM44FromRowMajor3x3(&toXYZ_3x3.vals[0][0]);
}
// static
@@ -978,25 +894,22 @@
switch (transfer) {
case ColorSpace::TransferID::LINEAR:
case ColorSpace::TransferID::LINEAR_HDR:
+ *fn = SkNamedTransferFn::kLinear;
return true;
case ColorSpace::TransferID::GAMMA18:
fn->g = 1.801f;
return true;
case ColorSpace::TransferID::GAMMA22:
- fn->g = 2.2f;
+ *fn = SkNamedTransferFnExt::kRec470SystemM;
return true;
case ColorSpace::TransferID::GAMMA24:
fn->g = 2.4f;
return true;
case ColorSpace::TransferID::GAMMA28:
- fn->g = 2.8f;
+ *fn = SkNamedTransferFnExt::kRec470SystemBG;
return true;
case ColorSpace::TransferID::SMPTE240M:
- fn->a = 0.899626676224f;
- fn->b = 0.100373323776f;
- fn->c = 0.250000000000f;
- fn->d = 0.091286342118f;
- fn->g = 2.222222222222f;
+ *fn = SkNamedTransferFnExt::kSMPTE_ST_240;
return true;
case ColorSpace::TransferID::BT709:
case ColorSpace::TransferID::SMPTE170M:
@@ -1011,33 +924,29 @@
// Bearing all of that in mind, use the same transfer function as sRGB,
// which will allow more optimization, and will more closely match other
// media players.
- case ColorSpace::TransferID::IEC61966_2_1:
- case ColorSpace::TransferID::IEC61966_2_1_HDR:
- fn->a = 0.947867345704f;
- fn->b = 0.052132654296f;
- fn->c = 0.077399380805f;
- fn->d = 0.040449937172f;
- fn->g = 2.400000000000f;
+ case ColorSpace::TransferID::SRGB:
+ case ColorSpace::TransferID::SRGB_HDR:
+ *fn = SkNamedTransferFnExt::kSRGB;
return true;
case ColorSpace::TransferID::BT709_APPLE:
- fn->g = 1.961000000000f;
+ *fn = SkNamedTransferFnExt::kRec709Apple;
return true;
case ColorSpace::TransferID::SMPTEST428_1:
- fn->a = 1.034080527699f; // (52.37 / 48.0) ^ (1.0 / 2.6) per ITU-T H.273.
- fn->g = 2.600000000000f;
+ *fn = SkNamedTransferFnExt::kSMPTE_ST_428_1;
return true;
case ColorSpace::TransferID::IEC61966_2_4:
- // This could potentially be represented the same as IEC61966_2_1, but
- // it handles negative values differently.
+ // This could potentially be represented the same as SRGB, but it handles
+ // negative values differently.
break;
- case ColorSpace::TransferID::ARIB_STD_B67:
+ case ColorSpace::TransferID::HLG:
case ColorSpace::TransferID::BT1361_ECG:
case ColorSpace::TransferID::LOG:
case ColorSpace::TransferID::LOG_SQRT:
- case ColorSpace::TransferID::SMPTEST2084:
+ case ColorSpace::TransferID::PQ:
case ColorSpace::TransferID::CUSTOM:
case ColorSpace::TransferID::CUSTOM_HDR:
case ColorSpace::TransferID::PIECEWISE_HDR:
+ case ColorSpace::TransferID::SCRGB_LINEAR_80_NITS:
case ColorSpace::TransferID::INVALID:
break;
}
@@ -1045,40 +954,49 @@
return false;
}
-bool ColorSpace::GetTransferFunction(skcms_TransferFunction* fn) const {
- if (transfer_ == TransferID::CUSTOM || transfer_ == TransferID::CUSTOM_HDR) {
- fn->a = transfer_params_[0];
- fn->b = transfer_params_[1];
- fn->c = transfer_params_[2];
- fn->d = transfer_params_[3];
- fn->e = transfer_params_[4];
- fn->f = transfer_params_[5];
- fn->g = transfer_params_[6];
- return true;
- } else {
- return GetTransferFunction(transfer_, fn);
+bool ColorSpace::GetTransferFunction(
+ skcms_TransferFunction* fn,
+ absl::optional<float> sdr_white_level) const {
+ switch (transfer_) {
+ case TransferID::CUSTOM:
+ case TransferID::CUSTOM_HDR:
+ fn->a = transfer_params_[0];
+ fn->b = transfer_params_[1];
+ fn->c = transfer_params_[2];
+ fn->d = transfer_params_[3];
+ fn->e = transfer_params_[4];
+ fn->f = transfer_params_[5];
+ fn->g = transfer_params_[6];
+ return true;
+ case TransferID::SCRGB_LINEAR_80_NITS:
+ if (sdr_white_level) {
+ fn->a = 80.f / *sdr_white_level;
+ fn->b = 0;
+ fn->c = 0;
+ fn->d = 0;
+ fn->e = 0;
+ fn->f = 0;
+ fn->g = 1;
+ return true;
+ } else {
+ // Using SCRGB_LINEAR_80_NITS without specifying an SDR white level is
+ // guaranteed to produce incorrect results.
+ return false;
+ }
+ default:
+ return GetTransferFunction(transfer_, fn);
}
}
-bool ColorSpace::GetInverseTransferFunction(skcms_TransferFunction* fn) const {
- if (!GetTransferFunction(fn))
+bool ColorSpace::GetInverseTransferFunction(
+ skcms_TransferFunction* fn,
+ absl::optional<float> sdr_white_level) const {
+ if (!GetTransferFunction(fn, sdr_white_level))
return false;
*fn = SkTransferFnInverse(*fn);
return true;
}
-bool ColorSpace::GetSDRWhiteLevel(float* sdr_white_level) const {
- if (transfer_ != TransferID::SMPTEST2084 &&
- transfer_ != TransferID::ARIB_STD_B67) {
- return false;
- }
- if (transfer_params_[0] == 0.0f)
- *sdr_white_level = kDefaultSDRWhiteLevel;
- else
- *sdr_white_level = transfer_params_[0];
- return true;
-}
-
bool ColorSpace::GetPiecewiseHDRParams(float* sdr_joint,
float* hdr_level) const {
if (transfer_ != TransferID::PIECEWISE_HDR)
@@ -1088,8 +1006,8 @@
return true;
}
-void ColorSpace::GetTransferMatrix(int bit_depth,
- skia::Matrix44* matrix) const {
+SkM44 ColorSpace::GetTransferMatrix(int bit_depth) const {
+ bit_depth = BitDepthWithWorkaroundApplied(bit_depth);
DCHECK_GE(bit_depth, 8);
// If chroma samples are real numbers in the range of −0.5 to 0.5, an offset
// of 0.5 is added to get real numbers in the range of 0 to 1. When
@@ -1106,8 +1024,7 @@
switch (matrix_) {
case ColorSpace::MatrixID::RGB:
case ColorSpace::MatrixID::INVALID:
- matrix->setIdentity();
- return;
+ return SkM44();
case ColorSpace::MatrixID::BT709:
Kr = 0.2126f;
@@ -1135,8 +1052,7 @@
-0.25f, 0.5f, -0.25f, chroma_0_5, // Cg
0.5f, 0.0f, -0.5f, chroma_0_5, // Co
0.0f, 0.0f, 0.0f, 1.0f};
- matrix->setRowMajorf(data);
- return;
+ return SkM44::RowMajor(data);
}
// BT2020_CL is a special case.
@@ -1150,8 +1066,7 @@
Kr, 1.0f - Kr - Kb, Kb, 0.0f, // Y
0.0f, 0.0f, 1.0f, 0.0f, // B
0.0f, 0.0f, 0.0f, 1.0f};
- matrix->setRowMajorf(data);
- return;
+ return SkM44::RowMajor(data);
}
case ColorSpace::MatrixID::BT2020_NCL:
@@ -1168,16 +1083,14 @@
0.0f, 0.0f, 0.0f, 1.0f,
};
// clang-format on
- matrix->setRowMajorf(data);
- return;
+ return SkM44::RowMajor(data);
}
case ColorSpace::MatrixID::GBR: {
float data[16] = {0.0f, 1.0f, 0.0f, 0.0f, // G
0.0f, 0.0f, 1.0f, 0.0f, // B
1.0f, 0.0f, 0.0f, 0.0f, // R
0.0f, 0.0f, 0.0f, 1.0f};
- matrix->setRowMajorf(data);
- return;
+ return SkM44::RowMajor(data);
}
}
float Kg = 1.0f - Kr - Kb;
@@ -1191,17 +1104,16 @@
0.0f, 0.0f, 0.0f, 1.0f,
};
// clang-format on
- matrix->setRowMajorf(data);
+ return SkM44::RowMajor(data);
}
-void ColorSpace::GetRangeAdjustMatrix(int bit_depth,
- skia::Matrix44* matrix) const {
+SkM44 ColorSpace::GetRangeAdjustMatrix(int bit_depth) const {
+ bit_depth = BitDepthWithWorkaroundApplied(bit_depth);
DCHECK_GE(bit_depth, 8);
switch (range_) {
case RangeID::FULL:
case RangeID::INVALID:
- matrix->setIdentity();
- return;
+ return SkM44();
case RangeID::DERIVED:
case RangeID::LIMITED:
@@ -1218,11 +1130,9 @@
case MatrixID::RGB:
case MatrixID::GBR:
case MatrixID::INVALID:
- case MatrixID::YCOCG: {
- matrix->setScale(scale_y, scale_y, scale_y);
- matrix->postTranslate(-16.0f / 219.0f, -16.0f / 219.0f, -16.0f / 219.0f);
- break;
- }
+ case MatrixID::YCOCG:
+ return SkM44::Scale(scale_y, scale_y, scale_y)
+ .postTranslate(-16.0f / 219.0f, -16.0f / 219.0f, -16.0f / 219.0f);
case MatrixID::BT709:
case MatrixID::FCC:
@@ -1235,14 +1145,16 @@
const float a_uv = 224 << shift;
const float scale_uv = c / a_uv;
const float translate_uv = (a_uv - c) / (2.0f * a_uv);
- matrix->setScale(scale_y, scale_uv, scale_uv);
- matrix->postTranslate(-16.0f / 219.0f, translate_uv, translate_uv);
- break;
+ return SkM44::Scale(scale_y, scale_uv, scale_uv)
+ .postTranslate(-16.0f / 219.0f, translate_uv, translate_uv);
}
}
+ NOTREACHED();
+ return SkM44();
}
bool ColorSpace::ToSkYUVColorSpace(int bit_depth, SkYUVColorSpace* out) const {
+ bit_depth = BitDepthWithWorkaroundApplied(bit_depth);
switch (matrix_) {
case MatrixID::BT709:
*out = range_ == RangeID::FULL ? kRec709_Full_SkYUVColorSpace
diff --git a/ui/gfx/color_space.h b/ui/gfx/color_space.h
index 169ef2f..2bb608f 100644
--- a/ui/gfx/color_space.h
+++ b/ui/gfx/color_space.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -12,21 +12,17 @@
#include "base/gtest_prod_util.h"
#include "build/build_config.h"
-#if !defined(STARBOARD)
+#include "skia/ext/skcolorspace_trfn.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkRefCnt.h"
-#endif // !defined(STARBOARD)
#include "ui/gfx/color_space_export.h"
struct skcms_Matrix3x3;
struct skcms_TransferFunction;
class SkColorSpace;
-#if !defined(STARBOARD)
+class SkM44;
+struct SkColorSpacePrimaries;
enum SkYUVColorSpace : int;
-#endif // !defined(STARBOARD)
-
-namespace skia {
-class Matrix44;
-} // namespace skia
// These forward declarations are used to give IPC code friend access to private
// fields of gfx::ColorSpace for the purpose of serialization and
@@ -44,6 +40,14 @@
// Used to serialize a gfx::ColorSpace through the GPU command buffer.
struct _GLcolorSpace;
+namespace media {
+namespace stable {
+namespace mojom {
+class ColorSpaceDataView;
+} // namespace mojom
+} // namespace stable
+} // namespace media
+
namespace gfx {
enum class ContentColorUsage : uint8_t;
@@ -59,6 +63,7 @@
public:
enum class PrimaryID : uint8_t {
INVALID,
+ // BT709 is also the primaries for SRGB.
BT709,
BT470M,
BT470BG,
@@ -68,7 +73,7 @@
BT2020,
SMPTEST428_1,
SMPTEST431_2,
- SMPTEST432_1,
+ P3,
XYZ_D50,
ADOBE_RGB,
// Corresponds the the primaries of the "Generic RGB" profile used in the
@@ -98,15 +103,17 @@
LOG_SQRT,
IEC61966_2_4,
BT1361_ECG,
- IEC61966_2_1,
+ SRGB,
BT2020_10,
BT2020_12,
- SMPTEST2084,
+ // Perceptual quantizer, also known as SMPTEST2084.
+ PQ,
SMPTEST428_1,
- ARIB_STD_B67, // AKA hybrid-log gamma, HLG.
- // The same as IEC61966_2_1 on the interval [0, 1], with the nonlinear
- // segment continuing beyond 1 and point symmetry defining values below 0.
- IEC61966_2_1_HDR,
+ // Hybrid-log gamma, also known as ARIB_STD_B67.
+ HLG,
+ // The same as SRGB on the interval [0, 1], with the nonlinear segment
+ // continuing beyond 1 and point symmetry defining values below 0.
+ SRGB_HDR,
// The same as LINEAR but is defined for all real values.
LINEAR_HDR,
// A parametric transfer function defined by |transfer_params_|.
@@ -115,7 +122,12 @@
CUSTOM_HDR,
// An HDR transfer function that is piecewise sRGB, and piecewise linear.
PIECEWISE_HDR,
- kMaxValue = PIECEWISE_HDR,
+ // An HDR transfer function that is linear, with the value 1 at 80 nits.
+ // This transfer function is not SDR-referred, and therefore can only be
+ // used (e.g, by ToSkColorSpace or GetTransferFunction) when an SDR white
+ // level is specified.
+ SCRGB_LINEAR_80_NITS,
+ kMaxValue = SCRGB_LINEAR_80_NITS,
};
enum class MatrixID : uint8_t {
@@ -163,19 +175,19 @@
const skcms_Matrix3x3* custom_primary_matrix,
const skcms_TransferFunction* cunstom_transfer_fn);
- explicit ColorSpace(const SkColorSpace& sk_color_space);
+ explicit ColorSpace(const SkColorSpace& sk_color_space, bool is_hdr = false);
// Returns true if this is not the default-constructor object.
bool IsValid() const;
static constexpr ColorSpace CreateSRGB() {
- return ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1, MatrixID::RGB,
+ return ColorSpace(PrimaryID::BT709, TransferID::SRGB, MatrixID::RGB,
RangeID::FULL);
}
static constexpr ColorSpace CreateDisplayP3D65() {
- return ColorSpace(PrimaryID::SMPTEST432_1, TransferID::IEC61966_2_1,
- MatrixID::RGB, RangeID::FULL);
+ return ColorSpace(PrimaryID::P3, TransferID::SRGB, MatrixID::RGB,
+ RangeID::FULL);
}
static ColorSpace CreateCustom(const skcms_Matrix3x3& to_XYZD50,
const skcms_TransferFunction& fn);
@@ -189,29 +201,40 @@
// Extended sRGB matches sRGB for values in [0, 1], and extends the transfer
// function to all real values.
static constexpr ColorSpace CreateExtendedSRGB() {
- return ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1_HDR,
- MatrixID::RGB, RangeID::FULL);
+ return ColorSpace(PrimaryID::BT709, TransferID::SRGB_HDR, MatrixID::RGB,
+ RangeID::FULL);
}
// scRGB uses the same primaries as sRGB but has a linear transfer function
- // for all real values, and a white point of kDefaultScrgbLinearSdrWhiteLevel.
- static constexpr ColorSpace CreateSCRGBLinear() {
+ // for all real values.
+ static constexpr ColorSpace CreateSRGBLinear() {
return ColorSpace(PrimaryID::BT709, TransferID::LINEAR_HDR, MatrixID::RGB,
RangeID::FULL);
}
- // Allows specifying a custom SDR white level. Only used on Windows.
- static ColorSpace CreateSCRGBLinear(float sdr_white_level);
+
+ // scRGB uses the same primaries as sRGB but has a linear transfer function
+ // for all real values, and an SDR white level of 80 nits.
+ static constexpr ColorSpace CreateSCRGBLinear80Nits() {
+ return ColorSpace(PrimaryID::BT709, TransferID::SCRGB_LINEAR_80_NITS,
+ MatrixID::RGB, RangeID::FULL);
+ }
// HDR10 uses BT.2020 primaries with SMPTE ST 2084 PQ transfer function.
static constexpr ColorSpace CreateHDR10() {
- return ColorSpace(PrimaryID::BT2020, TransferID::SMPTEST2084, MatrixID::RGB,
+ return ColorSpace(PrimaryID::BT2020, TransferID::PQ, MatrixID::RGB,
RangeID::FULL);
}
- // Allows specifying a custom SDR white level. Only used on Windows.
- static ColorSpace CreateHDR10(float sdr_white_level);
// HLG uses the BT.2020 primaries with the ARIB_STD_B67 transfer function.
- static ColorSpace CreateHLG();
+ static constexpr ColorSpace CreateHLG() {
+ return ColorSpace(PrimaryID::BT2020, TransferID::HLG, MatrixID::RGB,
+ RangeID::FULL);
+ }
+
+ // An extended sRGB ColorSpace that matches the sRGB EOTF but extends to
+ // 4.99x the headroom of SDR brightness. Designed for a 10 bpc buffer format.
+ // Uses P3 primaries. An HDR ColorSpace suitable for blending and compositing.
+ static ColorSpace CreateExtendedSRGB10Bit();
// Create a piecewise-HDR color space.
// - If |primaries| is CUSTOM, then |custom_primary_matrix| must be
@@ -232,8 +255,8 @@
static constexpr ColorSpace CreateJpeg() {
// TODO(ccameron): Determine which primaries and transfer function were
// intended here.
- return ColorSpace(PrimaryID::BT709, TransferID::IEC61966_2_1,
- MatrixID::SMPTE170M, RangeID::FULL);
+ return ColorSpace(PrimaryID::BT709, TransferID::SRGB, MatrixID::SMPTE170M,
+ RangeID::FULL);
}
static constexpr ColorSpace CreateREC601() {
return ColorSpace(PrimaryID::SMPTE170M, TransferID::SMPTE170M,
@@ -244,39 +267,49 @@
RangeID::LIMITED);
}
- // On macOS and on ChromeOS, sRGB's (1,1,1) always coincides with PQ's 100
- // nits (which may not be 100 physical nits). On Windows, sRGB's (1,1,1)
- // maps to scRGB linear's (1,1,1) when the SDR white level is set to 80 nits.
- // See also kDefaultScrgbLinearSdrWhiteLevel.
- static constexpr float kDefaultSDRWhiteLevel = 100.f;
-
- // The default white level in nits for scRGB linear color space. On Windows,
- // sRGB's (1,1,1) maps to scRGB linear's (1,1,1) when the SDR white level is
- // set to 80 nits. On Mac and ChromeOS, sRGB's (1,1,1) maps to PQ's 100 nits.
- // Using a platform specific value here satisfies both constraints.
-#if defined(OS_WIN)
- static constexpr float kDefaultScrgbLinearSdrWhiteLevel = 80.0f;
-#else
- static constexpr float kDefaultScrgbLinearSdrWhiteLevel =
- kDefaultSDRWhiteLevel;
-#endif // OS_WIN
+ // The default number of nits for SDR white. This is used for transformations
+ // between color spaces that do not specify an SDR white for tone mapping
+ // (e.g, in 2D canvas).
+ static constexpr float kDefaultSDRWhiteLevel = 203.f;
bool operator==(const ColorSpace& other) const;
bool operator!=(const ColorSpace& other) const;
bool operator<(const ColorSpace& other) const;
size_t GetHash() const;
+#if defined(STARBOARD)
std::string ToString() const {
// TODO: Refine ColorSpace::ToString().
return "";
}
+#else // defined(STARBOARD)
+ std::string ToString() const;
+#endif // defined(STARBOARD)
bool IsWide() const;
// Returns true if the transfer function is an HDR one (SMPTE 2084, HLG, etc).
+#if defined(STARBOARD)
bool IsHDR() const {
- // TODO: Refine ColorSpace::IsHDR().
- return false;
- }
+ return transfer_ == TransferID::PQ || transfer_ == TransferID::HLG ||
+ transfer_ == TransferID::LINEAR_HDR ||
+ transfer_ == TransferID::SRGB_HDR ||
+ transfer_ == TransferID::CUSTOM_HDR ||
+ transfer_ == TransferID::PIECEWISE_HDR ||
+ transfer_ == TransferID::SCRGB_LINEAR_80_NITS;
+}
+#else // defined(STARBOARD)
+ bool IsHDR() const;
+#endif // defined(STARBOARD)
+
+ // Returns true if there exists a default tone mapping that should be applied
+ // when drawing content with this color space. This is true for spaces with
+ // the PQ and HLG transfer functions.
+ bool IsToneMappedByDefault() const;
+
+ // Returns true if the color space's interpretation is affected by the SDR
+ // white level parameter. This is true for spaces with the PQ, HLG, and
+ // SCRGB_LINEAR_80_NITS transfer functions.
+ bool IsAffectedBySDRWhiteLevel() const;
// Returns true if the encoded values can be outside of the 0.0-1.0 range.
bool FullRangeEncodedValues() const;
@@ -305,23 +338,17 @@
// the caller but replacing the matrix and range with the given values.
ColorSpace GetWithMatrixAndRange(MatrixID matrix, RangeID range) const;
- // If this color space has a PQ or scRGB linear transfer function, then return
- // |this| with its SDR white level set to |sdr_white_level|. Otherwise return
- // |this| unmodified.
- ColorSpace GetWithSDRWhiteLevel(float sdr_white_level) const;
-
-#if !defined(STARBOARD)
// This will return nullptr for non-RGB spaces, spaces with non-FULL
- // range, and unspecified spaces.
- sk_sp<SkColorSpace> ToSkColorSpace() const;
-#endif // !defined(STARBOARD)
+ // range, unspecified spaces, and spaces that require but are not provided
+ // and SDR white level.
+ sk_sp<SkColorSpace> ToSkColorSpace(
+ absl::optional<float> sdr_white_level = absl::nullopt) const;
// Return a GLcolorSpace value that is valid for the lifetime of |this|. This
// function is used to serialize ColorSpace objects across the GPU command
// buffer.
const _GLcolorSpace* AsGLColorSpace() const;
-#if !defined(STARBOARD)
// For YUV color spaces, return the closest SkYUVColorSpace. Returns true if a
// close match is found. Otherwise, leaves *out unchanged and returns false.
// If |matrix_id| is MatrixID::BT2020_NCL and |bit_depth| is provided, a bit
@@ -330,17 +357,22 @@
bool ToSkYUVColorSpace(SkYUVColorSpace* out) const {
return ToSkYUVColorSpace(kDefaultBitDepth, out);
}
-#endif // !defined(STARBOARD)
+ // Return the RGB and whitepoint coordinates of the ColorSpace's
+ // chromaticity. Assumes D65 whitepoint in the case of a custom PrimaryID.
+ SkColorSpacePrimaries GetPrimaries() const;
void GetPrimaryMatrix(skcms_Matrix3x3* to_XYZD50) const;
- void GetPrimaryMatrix(skia::Matrix44* to_XYZD50) const;
- bool GetTransferFunction(skcms_TransferFunction* fn) const;
- bool GetInverseTransferFunction(skcms_TransferFunction* fn) const;
+ SkM44 GetPrimaryMatrix() const;
- // Returns the SDR white level specified for the PQ or HLG transfer functions.
- // If no value was specified, then use kDefaultSDRWhiteLevel. If the transfer
- // function is not PQ then return false.
- bool GetSDRWhiteLevel(float* sdr_white_level) const;
+ // Retrieve the parametric transfer function for this color space. Returns
+ // false if none is available, or if `sdr_white_level` is required but
+ // not specified.
+ bool GetTransferFunction(
+ skcms_TransferFunction* fn,
+ absl::optional<float> sdr_white_level = absl::nullopt) const;
+ bool GetInverseTransferFunction(
+ skcms_TransferFunction* fn,
+ absl::optional<float> sdr_white_level = absl::nullopt) const;
// Returns the parameters for a PIECEWISE_HDR transfer function. See
// CreatePiecewiseHDR for parameter meanings.
@@ -348,12 +380,36 @@
// Returns the transfer matrix for |bit_depth|. For most formats, this is the
// RGB to YUV matrix.
- void GetTransferMatrix(int bit_depth, skia::Matrix44* matrix) const;
+ SkM44 GetTransferMatrix(int bit_depth) const;
// Returns the range adjust matrix that converts from |range_| to full range
// for |bit_depth|.
- void GetRangeAdjustMatrix(int bit_depth, skia::Matrix44* matrix) const;
+ SkM44 GetRangeAdjustMatrix(int bit_depth) const;
+#if defined(STARBOARD)
+ // Returns the current primary ID.
+ // Note: if SetCustomPrimaries() has been used, the primary ID returned
+ // may have been set to PrimaryID::CUSTOM, or been coerced to another
+ // PrimaryID if it was very close.
+ PrimaryID GetPrimaryID() const {
+ return primaries_;
+ }
+
+ // Returns the current transfer ID.
+ TransferID GetTransferID() const {
+ return transfer_;
+ }
+
+ // Returns the current matrix ID.
+ MatrixID GetMatrixID() const {
+ return matrix_;
+ }
+
+ // Returns the current range ID.
+ RangeID GetRangeID() const {
+ return range_;
+ }
+#else // defined(STARBOARD)
// Returns the current primary ID.
// Note: if SetCustomPrimaries() has been used, the primary ID returned
// may have been set to PrimaryID::CUSTOM, or been coerced to another
@@ -368,11 +424,17 @@
// Returns the current range ID.
RangeID GetRangeID() const;
+#endif // defined(STARBOARD)
// Returns true if the transfer function is defined by an
- // skcms_TransferFunction which is extended to all real values.
+ // skcms_TransferFunction which is extended to all real values. This is true
+ // unless the color space has a non-RGB matrix.
bool HasExtendedSkTransferFn() const;
+ // Returns true if the transfer function values of this color space match
+ // those of the passed in skcms_TransferFunction.
+ bool IsTransferFunctionEqualTo(const skcms_TransferFunction& fn) const;
+
// Returns true if each color in |other| can be expressed in this color space.
bool Contains(const ColorSpace& other) const;
@@ -380,6 +442,9 @@
// The default bit depth assumed by ToSkYUVColorSpace().
static constexpr int kDefaultBitDepth = 8;
+ static SkColorSpacePrimaries GetColorSpacePrimaries(
+ PrimaryID,
+ const skcms_Matrix3x3* custom_primary_matrix);
static void GetPrimaryMatrix(PrimaryID, skcms_Matrix3x3* to_XYZD50);
static bool GetTransferFunction(TransferID, skcms_TransferFunction* fn);
static size_t TransferParamCount(TransferID);
@@ -393,7 +458,7 @@
RangeID range_ = RangeID::INVALID;
// Only used if primaries_ is PrimaryID::CUSTOM.
- float custom_primary_matrix_[9] = {0, 0, 0, 0, 0, 0, 0, 0};
+ float custom_primary_matrix_[9] = {0};
// Parameters for the transfer function. The interpretation depends on
// |transfer_|. Only TransferParamCount() of these parameters are used, all
@@ -401,11 +466,13 @@
// - CUSTOM and CUSTOM_HDR: Entries A through G of the skcms_TransferFunction
// structure in alphabetical order.
// - SMPTEST2084: SDR white point.
- float transfer_params_[7] = {0, 0, 0, 0, 0, 0, 0};
+ float transfer_params_[7] = {0};
friend struct IPC::ParamTraits<gfx::ColorSpace>;
friend struct mojo::StructTraits<gfx::mojom::ColorSpaceDataView,
gfx::ColorSpace>;
+ friend struct mojo::StructTraits<media::stable::mojom::ColorSpaceDataView,
+ gfx::ColorSpace>;
};
// Stream operator so ColorSpace can be used in assertion statements.
diff --git a/ui/gfx/color_space_export.h b/ui/gfx/color_space_export.h
index a0402b7..2474ed9 100644
--- a/ui/gfx/color_space_export.h
+++ b/ui/gfx/color_space_export.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/color_space_unittest.cc b/ui/gfx/color_space_unittest.cc
index 2fcff5f..126eaa8 100644
--- a/ui/gfx/color_space_unittest.cc
+++ b/ui/gfx/color_space_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -14,20 +14,18 @@
namespace {
// Returns the L-infty difference of u and v.
-float Diff(const skia::Vector4& u, const skia::Vector4& v) {
- float result = 0;
- for (size_t i = 0; i < 4; ++i)
- result = std::max(result, std::abs(u.fData[i] - v.fData[i]));
- return result;
+float Diff(const SkV4& u, const SkV4& v) {
+ return std::max({std::abs(u.x - v.x), std::abs(u.y - v.y),
+ std::abs(u.z - v.z), std::abs(u.w - v.w)});
}
TEST(ColorSpace, RGBToYUV) {
const float kEpsilon = 1.0e-3f;
const size_t kNumTestRGBs = 3;
- skia::Vector4 test_rgbs[kNumTestRGBs] = {
- skia::Vector4(1.f, 0.f, 0.f, 1.f),
- skia::Vector4(0.f, 1.f, 0.f, 1.f),
- skia::Vector4(0.f, 0.f, 1.f, 1.f),
+ SkV4 test_rgbs[kNumTestRGBs] = {
+ {1.f, 0.f, 0.f, 1.f},
+ {0.f, 1.f, 0.f, 1.f},
+ {0.f, 0.f, 1.f, 1.f},
};
const size_t kNumColorSpaces = 4;
@@ -38,45 +36,43 @@
gfx::ColorSpace::CreateXYZD50(),
};
- skia::Vector4 expected_yuvs[kNumColorSpaces][kNumTestRGBs] = {
+ SkV4 expected_yuvs[kNumColorSpaces][kNumTestRGBs] = {
// REC601
{
- skia::Vector4(0.3195f, 0.3518f, 0.9392f, 1.0000f),
- skia::Vector4(0.5669f, 0.2090f, 0.1322f, 1.0000f),
- skia::Vector4(0.1607f, 0.9392f, 0.4286f, 1.0000f),
+ {0.3195f, 0.3518f, 0.9392f, 1.0000f},
+ {0.5669f, 0.2090f, 0.1322f, 1.0000f},
+ {0.1607f, 0.9392f, 0.4286f, 1.0000f},
},
// REC709
{
- skia::Vector4(0.2453f, 0.3994f, 0.9392f, 1.0000f),
- skia::Vector4(0.6770f, 0.1614f, 0.1011f, 1.0000f),
- skia::Vector4(0.1248f, 0.9392f, 0.4597f, 1.0000f),
+ {0.2453f, 0.3994f, 0.9392f, 1.0000f},
+ {0.6770f, 0.1614f, 0.1011f, 1.0000f},
+ {0.1248f, 0.9392f, 0.4597f, 1.0000f},
},
// Jpeg
{
- skia::Vector4(0.2990f, 0.3313f, 1.0000f, 1.0000f),
- skia::Vector4(0.5870f, 0.1687f, 0.0813f, 1.0000f),
- skia::Vector4(0.1140f, 1.0000f, 0.4187f, 1.0000f),
+ {0.2990f, 0.3313f, 1.0000f, 1.0000f},
+ {0.5870f, 0.1687f, 0.0813f, 1.0000f},
+ {0.1140f, 1.0000f, 0.4187f, 1.0000f},
},
// XYZD50
{
- skia::Vector4(1.0000f, 0.0000f, 0.0000f, 1.0000f),
- skia::Vector4(0.0000f, 1.0000f, 0.0000f, 1.0000f),
- skia::Vector4(0.0000f, 0.0000f, 1.0000f, 1.0000f),
+ {1.0000f, 0.0000f, 0.0000f, 1.0000f},
+ {0.0000f, 1.0000f, 0.0000f, 1.0000f},
+ {0.0000f, 0.0000f, 1.0000f, 1.0000f},
},
};
for (size_t i = 0; i < kNumColorSpaces; ++i) {
- skia::Matrix44 transfer;
- color_spaces[i].GetTransferMatrix(/*bit_depth=*/8, &transfer);
+ SkM44 transfer = color_spaces[i].GetTransferMatrix(/*bit_depth=*/8);
- skia::Matrix44 range_adjust;
- color_spaces[i].GetRangeAdjustMatrix(/*bit_depth=*/8, &range_adjust);
+ SkM44 range_adjust = color_spaces[i].GetRangeAdjustMatrix(/*bit_depth=*/8);
- skia::Matrix44 range_adjust_inv;
- range_adjust.invert(&range_adjust_inv);
+ SkM44 range_adjust_inv;
+ EXPECT_TRUE(range_adjust.invert(&range_adjust_inv));
for (size_t j = 0; j < kNumTestRGBs; ++j) {
- skia::Vector4 yuv = range_adjust_inv * transfer * test_rgbs[j];
+ SkV4 yuv = range_adjust_inv * transfer * test_rgbs[j];
EXPECT_LT(Diff(yuv, expected_yuvs[i][j]), kEpsilon);
}
}
@@ -85,9 +81,9 @@
TEST(ColorSpace, RangeAdjust) {
const float kEpsilon = 1.0e-3f;
const size_t kNumTestYUVs = 2;
- skia::Vector4 test_yuvs[kNumTestYUVs] = {
- skia::Vector4(1.f, 1.f, 1.f, 1.f),
- skia::Vector4(0.f, 0.f, 0.f, 1.f),
+ SkV4 test_yuvs[kNumTestYUVs] = {
+ {1.f, 1.f, 1.f, 1.f},
+ {0.f, 0.f, 0.f, 1.f},
};
const size_t kNumBitDepths = 3;
@@ -102,84 +98,72 @@
ColorSpace::RangeID::LIMITED),
};
- skia::Vector4 expected_yuvs[kNumColorSpaces][kNumBitDepths][kNumTestYUVs] = {
+ SkV4 expected_yuvs[kNumColorSpaces][kNumBitDepths][kNumTestYUVs] = {
// REC601
{
// 8bpc
{
- skia::Vector4(235.f / 255.f, 239.5f / 255.f, 239.5f / 255.f,
- 1.0000f),
- skia::Vector4(16.f / 255.f, 15.5f / 255.f, 15.5f / 255.f,
- 1.0000f),
+ {235.f / 255.f, 239.5f / 255.f, 239.5f / 255.f, 1.0000f},
+ {16.f / 255.f, 15.5f / 255.f, 15.5f / 255.f, 1.0000f},
},
// 10bpc
{
- skia::Vector4(940.f / 1023.f, 959.5f / 1023.f, 959.5f / 1023.f,
- 1.0000f),
- skia::Vector4(64.f / 1023.f, 63.5f / 1023.f, 63.5f / 1023.f,
- 1.0000f),
+ {940.f / 1023.f, 959.5f / 1023.f, 959.5f / 1023.f, 1.0000f},
+ {64.f / 1023.f, 63.5f / 1023.f, 63.5f / 1023.f, 1.0000f},
},
// 12bpc
{
- skia::Vector4(3760.f / 4095.f, 3839.5f / 4095.f, 3839.5f / 4095.f,
- 1.0000f),
- skia::Vector4(256.f / 4095.f, 255.5f / 4095.f, 255.5f / 4095.f,
- 1.0000f),
+ {3760.f / 4095.f, 3839.5f / 4095.f, 3839.5f / 4095.f, 1.0000f},
+ {256.f / 4095.f, 255.5f / 4095.f, 255.5f / 4095.f, 1.0000f},
},
},
// Jpeg
{
// 8bpc
{
- skia::Vector4(1.0000f, 1.0000f, 1.0000f, 1.0000f),
- skia::Vector4(0.0000f, 0.0000f, 0.0000f, 1.0000f),
+ {1.0000f, 1.0000f, 1.0000f, 1.0000f},
+ {0.0000f, 0.0000f, 0.0000f, 1.0000f},
},
// 10bpc
{
- skia::Vector4(1.0000f, 1.0000f, 1.0000f, 1.0000f),
- skia::Vector4(0.0000f, 0.0000f, 0.0000f, 1.0000f),
+ {1.0000f, 1.0000f, 1.0000f, 1.0000f},
+ {0.0000f, 0.0000f, 0.0000f, 1.0000f},
},
// 12bpc
{
- skia::Vector4(1.0000f, 1.0000f, 1.0000f, 1.0000f),
- skia::Vector4(0.0000f, 0.0000f, 0.0000f, 1.0000f),
+ {1.0000f, 1.0000f, 1.0000f, 1.0000f},
+ {0.0000f, 0.0000f, 0.0000f, 1.0000f},
},
},
// YCoCg
{
// 8bpc
{
- skia::Vector4(235.f / 255.f, 235.f / 255.f, 235.f / 255.f,
- 1.0000f),
- skia::Vector4(16.f / 255.f, 16.f / 255.f, 16.f / 255.f, 1.0000f),
+ {235.f / 255.f, 235.f / 255.f, 235.f / 255.f, 1.0000f},
+ {16.f / 255.f, 16.f / 255.f, 16.f / 255.f, 1.0000f},
},
// 10bpc
{
- skia::Vector4(940.f / 1023.f, 940.f / 1023.f, 940.f / 1023.f,
- 1.0000f),
- skia::Vector4(64.f / 1023.f, 64.f / 1023.f, 64.f / 1023.f,
- 1.0000f),
+ {940.f / 1023.f, 940.f / 1023.f, 940.f / 1023.f, 1.0000f},
+ {64.f / 1023.f, 64.f / 1023.f, 64.f / 1023.f, 1.0000f},
},
// 12bpc
{
- skia::Vector4(3760.f / 4095.f, 3760.f / 4095.f, 3760.f / 4095.f,
- 1.0000f),
- skia::Vector4(256.f / 4095.f, 256.f / 4095.f, 256.f / 4095.f,
- 1.0000f),
+ {3760.f / 4095.f, 3760.f / 4095.f, 3760.f / 4095.f, 1.0000f},
+ {256.f / 4095.f, 256.f / 4095.f, 256.f / 4095.f, 1.0000f},
},
},
};
for (size_t i = 0; i < kNumColorSpaces; ++i) {
for (size_t j = 0; j < kNumBitDepths; ++j) {
- skia::Matrix44 range_adjust;
- color_spaces[i].GetRangeAdjustMatrix(bit_depths[j], &range_adjust);
+ SkM44 range_adjust = color_spaces[i].GetRangeAdjustMatrix(bit_depths[j]);
- skia::Matrix44 range_adjust_inv;
- range_adjust.invert(&range_adjust_inv);
+ SkM44 range_adjust_inv;
+ EXPECT_TRUE(range_adjust.invert(&range_adjust_inv));
for (size_t k = 0; k < kNumTestYUVs; ++k) {
- skia::Vector4 yuv = range_adjust_inv * test_yuvs[k];
+ SkV4 yuv = range_adjust_inv * test_yuvs[k];
EXPECT_LT(Diff(yuv, expected_yuvs[i][j][k]), kEpsilon);
}
}
@@ -191,7 +175,7 @@
// A linear transfer function being used for HDR should be blended using an
// sRGB-like transfer function.
- display_color_space = ColorSpace::CreateSCRGBLinear();
+ display_color_space = ColorSpace::CreateSRGBLinear();
EXPECT_FALSE(display_color_space.IsSuitableForBlending());
// If not used for HDR, a linear transfer function should be left unchanged.
@@ -200,7 +184,6 @@
}
TEST(ColorSpace, ConversionToAndFromSkColorSpace) {
- const size_t kNumTests = 5;
skcms_Matrix3x3 primary_matrix = {{
{0.205276f, 0.625671f, 0.060867f},
{0.149185f, 0.063217f, 0.744553f},
@@ -208,29 +191,32 @@
}};
skcms_TransferFunction transfer_fn = {2.1f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f};
- ColorSpace color_spaces[kNumTests] = {
- ColorSpace(ColorSpace::PrimaryID::BT709,
- ColorSpace::TransferID::IEC61966_2_1),
+ ColorSpace color_spaces[] = {
+ ColorSpace(ColorSpace::PrimaryID::BT709, ColorSpace::TransferID::SRGB),
ColorSpace(ColorSpace::PrimaryID::ADOBE_RGB,
- ColorSpace::TransferID::IEC61966_2_1),
- ColorSpace(ColorSpace::PrimaryID::SMPTEST432_1,
- ColorSpace::TransferID::LINEAR),
- ColorSpace(ColorSpace::PrimaryID::BT2020,
- ColorSpace::TransferID::IEC61966_2_1),
+ ColorSpace::TransferID::SRGB),
+ ColorSpace(ColorSpace::PrimaryID::P3, ColorSpace::TransferID::LINEAR),
+ ColorSpace(ColorSpace::PrimaryID::BT2020, ColorSpace::TransferID::SRGB),
ColorSpace::CreateCustom(primary_matrix, transfer_fn),
+ // HDR
+ ColorSpace::CreateSRGBLinear(),
};
- sk_sp<SkColorSpace> sk_color_spaces[kNumTests] = {
+ sk_sp<SkColorSpace> sk_color_spaces[] = {
SkColorSpace::MakeSRGB(),
SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kAdobeRGB),
SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear,
SkNamedGamut::kDisplayP3),
SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kRec2020),
SkColorSpace::MakeRGB(transfer_fn, primary_matrix),
+ // HDR
+ SkColorSpace::MakeSRGBLinear(),
};
+ static_assert(std::size(color_spaces) == std::size(sk_color_spaces), "");
+
// Test that converting from ColorSpace to SkColorSpace is producing an
// equivalent representation.
- for (size_t i = 0; i < kNumTests; ++i) {
+ for (size_t i = 0; i < std::size(color_spaces); ++i) {
EXPECT_TRUE(SkColorSpace::Equals(color_spaces[i].ToSkColorSpace().get(),
sk_color_spaces[i].get()))
<< " on iteration i = " << i;
@@ -240,69 +226,54 @@
// producing an equivalent representation; and then converting the converted
// ColorSpace back to SkColorSpace is also producing an equivalent
// representation.
- for (size_t i = 0; i < kNumTests; ++i) {
- const ColorSpace from_sk_color_space(*sk_color_spaces[i]);
+ for (size_t i = 0; i < std::size(color_spaces); ++i) {
+ const ColorSpace from_sk_color_space(*sk_color_spaces[i],
+ color_spaces[i].IsHDR());
EXPECT_EQ(color_spaces[i], from_sk_color_space);
EXPECT_TRUE(SkColorSpace::Equals(
sk_color_spaces[i].get(), from_sk_color_space.ToSkColorSpace().get()));
}
}
-TEST(ColorSpace, PQToSkColorSpace) {
- ColorSpace color_space;
- ColorSpace roundtrip_color_space;
- float roundtrip_sdr_white_level;
- const float kEpsilon = 1.e-5f;
+TEST(ColorSpace, PQAndHLGToSkColorSpace) {
+ const float kEpsilon = 1.0e-2f;
+ const auto hlg = ColorSpace::CreateHLG();
+ const auto pq = ColorSpace::CreateHDR10();
- // We expect that when a white point is specified, the conversion from
- // ColorSpace -> SkColorSpace -> ColorSpace be the identity. Because of
- // rounding error, this will not quite be the case.
- color_space = ColorSpace::CreateHDR10(50.f);
- roundtrip_color_space = ColorSpace(*color_space.ToSkColorSpace());
- EXPECT_TRUE(
- roundtrip_color_space.GetSDRWhiteLevel(&roundtrip_sdr_white_level));
- EXPECT_NEAR(50.f, roundtrip_sdr_white_level, kEpsilon);
- EXPECT_EQ(ColorSpace::TransferID::SMPTEST2084,
- roundtrip_color_space.GetTransferID());
+ // For each test case, `pq_signal` maps to `pq_nits`.
+ constexpr size_t kNumCases = 3;
+ float pq_signal[kNumCases] = {
+ 0.508078421517399f,
+ 0.5806888810416109f,
+ 0.6765848107833876,
+ };
+ float pq_nits[kNumCases] = {
+ 100,
+ 203,
+ 500,
+ };
+ const float kPQSignalFor203Nits = pq_signal[1];
+ const float kHLGSignalFor203Nits = 0.75f;
- // When no white level is specified, we should get an SkColorSpace that
- // specifies the default white level. Of note is that in the roundtrip, the
- // value of kDefaultSDRWhiteLevel gets baked in.
- color_space = ColorSpace::CreateHDR10();
- roundtrip_color_space = ColorSpace(*color_space.ToSkColorSpace());
- EXPECT_TRUE(
- roundtrip_color_space.GetSDRWhiteLevel(&roundtrip_sdr_white_level));
- EXPECT_NEAR(ColorSpace::kDefaultSDRWhiteLevel, roundtrip_sdr_white_level,
- kEpsilon);
-}
+ for (size_t i = 0; i < kNumCases; ++i) {
+ const float sdr_white_level = pq_nits[i];
+ sk_sp<SkColorSpace> sk_hlg = hlg.ToSkColorSpace(sdr_white_level);
+ sk_sp<SkColorSpace> sk_pq = pq.ToSkColorSpace(sdr_white_level);
-TEST(ColorSpace, HLGToSkColorSpace) {
- ColorSpace color_space;
- ColorSpace roundtrip_color_space;
- float roundtrip_sdr_white_level;
- const float kEpsilon = 1.0e-3f;
+ // The PQ signal that maps to `sdr_white_level` nits should map to 1.
+ skcms_TransferFunction pq_fn = {0};
+ sk_pq->transferFn(&pq_fn);
+ EXPECT_NEAR(1.f, skcms_TransferFunction_eval(&pq_fn, pq_signal[i]),
+ kEpsilon);
- // We expect that when a white point is specified, the conversion from
- // ColorSpace -> SkColorSpace -> ColorSpace be the identity. Because of
- // rounding error, this will not quite be the case.
- constexpr float kSDRWhiteLevel = 50.0f;
- color_space = ColorSpace::CreateHLG().GetWithSDRWhiteLevel(kSDRWhiteLevel);
- roundtrip_color_space = ColorSpace(*color_space.ToSkColorSpace());
- EXPECT_TRUE(
- roundtrip_color_space.GetSDRWhiteLevel(&roundtrip_sdr_white_level));
- EXPECT_FLOAT_EQ(kSDRWhiteLevel, roundtrip_sdr_white_level);
- EXPECT_EQ(ColorSpace::TransferID::ARIB_STD_B67,
- roundtrip_color_space.GetTransferID());
-
- // When no white level is specified, we should get an SkColorSpace that
- // specifies the default white level. Of note is that in the roundtrip, the
- // value of kDefaultSDRWhiteLevel gets baked in.
- color_space = ColorSpace::CreateHLG();
- roundtrip_color_space = ColorSpace(*color_space.ToSkColorSpace());
- EXPECT_TRUE(
- roundtrip_color_space.GetSDRWhiteLevel(&roundtrip_sdr_white_level));
- EXPECT_NEAR(ColorSpace::kDefaultSDRWhiteLevel, roundtrip_sdr_white_level,
- kEpsilon);
+ // The HLG signal value of 0.75 should always map to the same value that
+ // the PQ signal for 203 nits maps to.
+ skcms_TransferFunction hlg_fn = {0};
+ sk_hlg->transferFn(&hlg_fn);
+ EXPECT_NEAR(skcms_TransferFunction_eval(&pq_fn, kPQSignalFor203Nits),
+ skcms_TransferFunction_eval(&hlg_fn, kHLGSignalFor203Nits),
+ kEpsilon);
+ }
}
TEST(ColorSpace, MixedInvalid) {
@@ -316,9 +287,9 @@
}
TEST(ColorSpace, MixedSRGBWithRec601) {
- const ColorSpace expected_color_space = ColorSpace(
- ColorSpace::PrimaryID::BT709, ColorSpace::TransferID::IEC61966_2_1,
- ColorSpace::MatrixID::SMPTE170M, ColorSpace::RangeID::LIMITED);
+ const ColorSpace expected_color_space =
+ ColorSpace(ColorSpace::PrimaryID::BT709, ColorSpace::TransferID::SRGB,
+ ColorSpace::MatrixID::SMPTE170M, ColorSpace::RangeID::LIMITED);
ColorSpace color_space = ColorSpace::CreateSRGB();
color_space = color_space.GetWithMatrixAndRange(
ColorSpace::MatrixID::SMPTE170M, ColorSpace::RangeID::LIMITED);
@@ -327,9 +298,9 @@
}
TEST(ColorSpace, MixedHDR10WithRec709) {
- const ColorSpace expected_color_space = ColorSpace(
- ColorSpace::PrimaryID::BT2020, ColorSpace::TransferID::SMPTEST2084,
- ColorSpace::MatrixID::BT709, ColorSpace::RangeID::LIMITED);
+ const ColorSpace expected_color_space =
+ ColorSpace(ColorSpace::PrimaryID::BT2020, ColorSpace::TransferID::PQ,
+ ColorSpace::MatrixID::BT709, ColorSpace::RangeID::LIMITED);
ColorSpace color_space = ColorSpace::CreateHDR10();
color_space = color_space.GetWithMatrixAndRange(ColorSpace::MatrixID::BT709,
ColorSpace::RangeID::LIMITED);
@@ -347,57 +318,6 @@
EXPECT_EQ(color_space.GetRangeID(), ColorSpace::RangeID::LIMITED);
}
-TEST(ColorSpace, PQWhiteLevel) {
- constexpr float kCustomWhiteLevel = 200.f;
-
- ColorSpace color_space = ColorSpace::CreateHDR10(kCustomWhiteLevel);
- EXPECT_EQ(color_space.GetTransferID(), ColorSpace::TransferID::SMPTEST2084);
- float sdr_white_level;
- EXPECT_TRUE(color_space.GetSDRWhiteLevel(&sdr_white_level));
- EXPECT_EQ(sdr_white_level, kCustomWhiteLevel);
-
- color_space = ColorSpace::CreateHDR10();
- EXPECT_EQ(color_space.GetTransferID(), ColorSpace::TransferID::SMPTEST2084);
- EXPECT_TRUE(color_space.GetSDRWhiteLevel(&sdr_white_level));
- EXPECT_EQ(sdr_white_level, ColorSpace::kDefaultSDRWhiteLevel);
-
- color_space = color_space.GetWithSDRWhiteLevel(kCustomWhiteLevel);
- EXPECT_EQ(color_space.GetTransferID(), ColorSpace::TransferID::SMPTEST2084);
- EXPECT_TRUE(color_space.GetSDRWhiteLevel(&sdr_white_level));
- EXPECT_EQ(sdr_white_level, kCustomWhiteLevel);
-
- constexpr float kCustomWhiteLevel2 = kCustomWhiteLevel * 2;
- color_space = color_space.GetWithSDRWhiteLevel(kCustomWhiteLevel2);
- EXPECT_EQ(color_space.GetTransferID(), ColorSpace::TransferID::SMPTEST2084);
- EXPECT_TRUE(color_space.GetSDRWhiteLevel(&sdr_white_level));
- EXPECT_EQ(sdr_white_level, kCustomWhiteLevel2);
-}
-
-TEST(ColorSpace, LinearHDRWhiteLevel) {
- constexpr float kCustomWhiteLevel = 200.f;
- constexpr float kCustomSlope =
- ColorSpace::kDefaultScrgbLinearSdrWhiteLevel / kCustomWhiteLevel;
-
- ColorSpace color_space = ColorSpace::CreateSCRGBLinear(kCustomWhiteLevel);
- skcms_TransferFunction fn;
- EXPECT_EQ(color_space.GetTransferID(), ColorSpace::TransferID::CUSTOM_HDR);
- EXPECT_TRUE(color_space.GetTransferFunction(&fn));
- EXPECT_EQ(std::make_tuple(fn.g, fn.a, fn.b, fn.c, fn.d, fn.e, fn.f),
- std::make_tuple(1.f, kCustomSlope, 0.f, 0.f, 0.f, 0.f, 0.f));
-
- color_space = ColorSpace::CreateSCRGBLinear();
- EXPECT_EQ(color_space.GetTransferID(), ColorSpace::TransferID::LINEAR_HDR);
- EXPECT_TRUE(color_space.GetTransferFunction(&fn));
- EXPECT_EQ(std::make_tuple(fn.g, fn.a, fn.b, fn.c, fn.d, fn.e, fn.f),
- std::make_tuple(1.f, 1.f, 0.f, 0.f, 0.f, 0.f, 0.f));
-
- color_space = color_space.GetWithSDRWhiteLevel(kCustomWhiteLevel);
- EXPECT_EQ(color_space.GetTransferID(), ColorSpace::TransferID::CUSTOM_HDR);
- EXPECT_TRUE(color_space.GetTransferFunction(&fn));
- EXPECT_EQ(std::make_tuple(fn.g, fn.a, fn.b, fn.c, fn.d, fn.e, fn.f),
- std::make_tuple(1.f, kCustomSlope, 0.f, 0.f, 0.f, 0.f, 0.f));
-}
-
TEST(ColorSpace, ExpectationsMatchSRGB) {
ColorSpace::PrimaryID primary_ids[] = {
ColorSpace::PrimaryID::BT709,
@@ -409,7 +329,7 @@
ColorSpace::PrimaryID::BT2020,
ColorSpace::PrimaryID::SMPTEST428_1,
ColorSpace::PrimaryID::SMPTEST431_2,
- ColorSpace::PrimaryID::SMPTEST432_1,
+ ColorSpace::PrimaryID::P3,
ColorSpace::PrimaryID::XYZ_D50,
ColorSpace::PrimaryID::ADOBE_RGB,
ColorSpace::PrimaryID::APPLE_GENERIC_RGB,
@@ -421,10 +341,10 @@
skcms_Matrix3x3 to_XYZD50;
srgb.GetPrimaryMatrix(&to_XYZD50);
ColorSpace custom_srgb =
- ColorSpace::CreateCustom(to_XYZD50, ColorSpace::TransferID::IEC61966_2_1);
+ ColorSpace::CreateCustom(to_XYZD50, ColorSpace::TransferID::SRGB);
for (auto id : primary_ids) {
- ColorSpace color_space(id, ColorSpace::TransferID::IEC61966_2_1);
+ ColorSpace color_space(id, ColorSpace::TransferID::SRGB);
// The precomputed results for Contains(sRGB) should match the calculation
// performed on a custom color space with sRGB primaries.
EXPECT_EQ(color_space.Contains(srgb), color_space.Contains(custom_srgb));
diff --git a/ui/gfx/color_space_win.cc b/ui/gfx/color_space_win.cc
index 03886d4..3ca6659 100644
--- a/ui/gfx/color_space_win.cc
+++ b/ui/gfx/color_space_win.cc
@@ -1,11 +1,11 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/color_space_win.h"
#include "base/logging.h"
-#include "third_party/skia/include/third_party/skcms/skcms.h"
+#include "third_party/skia/modules/skcms/skcms.h"
namespace gfx {
@@ -79,7 +79,7 @@
case gfx::ColorSpace::PrimaryID::BT2020:
case gfx::ColorSpace::PrimaryID::SMPTEST428_1:
case gfx::ColorSpace::PrimaryID::SMPTEST431_2:
- case gfx::ColorSpace::PrimaryID::SMPTEST432_1:
+ case gfx::ColorSpace::PrimaryID::P3:
case gfx::ColorSpace::PrimaryID::XYZ_D50:
case gfx::ColorSpace::PrimaryID::ADOBE_RGB:
case gfx::ColorSpace::PrimaryID::APPLE_GENERIC_RGB:
@@ -106,10 +106,11 @@
break;
case gfx::ColorSpace::TransferID::LINEAR:
case gfx::ColorSpace::TransferID::LINEAR_HDR:
+ case gfx::ColorSpace::TransferID::SCRGB_LINEAR_80_NITS:
format.VideoTransferFunction = DXVA2_VideoTransFunc_10;
break;
- case gfx::ColorSpace::TransferID::IEC61966_2_1:
- case gfx::ColorSpace::TransferID::IEC61966_2_1_HDR:
+ case gfx::ColorSpace::TransferID::SRGB:
+ case gfx::ColorSpace::TransferID::SRGB_HDR:
format.VideoTransferFunction = DXVA2_VideoTransFunc_sRGB;
break;
@@ -119,9 +120,9 @@
case gfx::ColorSpace::TransferID::BT1361_ECG:
case gfx::ColorSpace::TransferID::BT2020_10:
case gfx::ColorSpace::TransferID::BT2020_12:
- case gfx::ColorSpace::TransferID::SMPTEST2084:
+ case gfx::ColorSpace::TransferID::PQ:
case gfx::ColorSpace::TransferID::SMPTEST428_1:
- case gfx::ColorSpace::TransferID::ARIB_STD_B67:
+ case gfx::ColorSpace::TransferID::HLG:
case gfx::ColorSpace::TransferID::BT709_APPLE:
case gfx::ColorSpace::TransferID::GAMMA18:
case gfx::ColorSpace::TransferID::GAMMA24:
@@ -148,8 +149,7 @@
// For RGB, we default to FULL
if (color_space.GetRangeID() == gfx::ColorSpace::RangeID::LIMITED) {
if (color_space.GetPrimaryID() == gfx::ColorSpace::PrimaryID::BT2020) {
- if (color_space.GetTransferID() ==
- gfx::ColorSpace::TransferID::SMPTEST2084) {
+ if (color_space.GetTransferID() == gfx::ColorSpace::TransferID::PQ) {
return DXGI_COLOR_SPACE_RGB_STUDIO_G2084_NONE_P2020;
} else {
return DXGI_COLOR_SPACE_RGB_STUDIO_G22_NONE_P2020;
@@ -159,8 +159,7 @@
}
} else {
if (color_space.GetPrimaryID() == gfx::ColorSpace::PrimaryID::BT2020) {
- if (color_space.GetTransferID() ==
- gfx::ColorSpace::TransferID::SMPTEST2084) {
+ if (color_space.GetTransferID() == gfx::ColorSpace::TransferID::PQ) {
return DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020;
} else {
return DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P2020;
@@ -169,7 +168,9 @@
if (color_space.GetTransferID() ==
gfx::ColorSpace::TransferID::LINEAR ||
color_space.GetTransferID() ==
- gfx::ColorSpace::TransferID::LINEAR_HDR) {
+ gfx::ColorSpace::TransferID::LINEAR_HDR ||
+ color_space.GetTransferID() ==
+ gfx::ColorSpace::TransferID::SCRGB_LINEAR_80_NITS) {
return DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709;
} else if (color_space.GetTransferID() ==
gfx::ColorSpace::TransferID::CUSTOM_HDR) {
@@ -185,13 +186,12 @@
}
} else {
if (color_space.GetPrimaryID() == gfx::ColorSpace::PrimaryID::BT2020) {
- if (color_space.GetTransferID() ==
- gfx::ColorSpace::TransferID::SMPTEST2084) {
+ if (color_space.GetTransferID() == gfx::ColorSpace::TransferID::PQ) {
return DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_LEFT_P2020;
// Could also be:
// DXGI_COLOR_SPACE_YCBCR_STUDIO_G2084_TOPLEFT_P2020
} else if (color_space.GetTransferID() ==
- gfx::ColorSpace::TransferID::ARIB_STD_B67) {
+ gfx::ColorSpace::TransferID::HLG) {
// Note: This may not always work. See https://crbug.com/1144260#c6.
return DXGI_COLOR_SPACE_YCBCR_STUDIO_GHLG_TOPLEFT_P2020;
} else {
@@ -234,7 +234,7 @@
DXGI_FORMAT ColorSpaceWin::GetDXGIFormat(const gfx::ColorSpace& color_space) {
// The PQ transfer function needs 10 bits.
- if (color_space.GetTransferID() == gfx::ColorSpace::TransferID::SMPTEST2084)
+ if (color_space.GetTransferID() == gfx::ColorSpace::TransferID::PQ)
return DXGI_FORMAT_R10G10B10A2_UNORM;
// Non-PQ HDR color spaces use half-float.
diff --git a/ui/gfx/color_space_win.h b/ui/gfx/color_space_win.h
index 1c71891..b2572bd 100644
--- a/ui/gfx/color_space_win.h
+++ b/ui/gfx/color_space_win.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,19 +7,13 @@
#include <d3d11.h>
#include <d3d9.h>
+#include <dxva2api.h>
// Must be included after d3d headers, use #if to avoid lint errors.
#if 1
#include <DXGIType.h>
#endif
-// Work around bug in this header by disabling the relevant warning for it.
-// https://connect.microsoft.com/VisualStudio/feedback/details/911260/dxva2api-h-in-win8-sdk-triggers-c4201-with-w4
-#pragma warning(push)
-#pragma warning(disable : 4201)
-#include <dxva2api.h>
-#pragma warning(pop)
-
#include "ui/gfx/color_space.h"
namespace gfx {
diff --git a/ui/gfx/color_transform.cc b/ui/gfx/color_transform.cc
index f53eb60..b5c4bbb 100644
--- a/ui/gfx/color_transform.cc
+++ b/ui/gfx/color_transform.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -13,10 +13,11 @@
#include "base/logging.h"
#include "base/notreached.h"
+#include "base/strings/string_number_conversions.h"
#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/third_party/skcms/skcms.h"
+#include "third_party/skia/include/core/SkM44.h"
+#include "third_party/skia/modules/skcms/skcms.h"
#include "ui/gfx/color_space.h"
-#include "ui/gfx/geometry/transform.h"
#include "ui/gfx/icc_profile.h"
#include "ui/gfx/skia_color_space_util.h"
@@ -47,9 +48,9 @@
return ss.str();
}
-Transform Invert(const Transform& t) {
- Transform ret = t;
- if (!t.GetInverse(&ret)) {
+SkM44 Invert(const SkM44& t) {
+ SkM44 ret = t;
+ if (!t.invert(&ret)) {
LOG(ERROR) << "Inverse should always be possible.";
}
return ret;
@@ -143,23 +144,38 @@
return 0;
}
-Transform GetTransferMatrix(const gfx::ColorSpace& color_space, int bit_depth) {
- skia::Matrix44 transfer_matrix;
- color_space.GetTransferMatrix(bit_depth, &transfer_matrix);
- return Transform(transfer_matrix);
+// Returns true if tone mapping will be a non-identity operation. Computes the
+// constants used by the tone mapping algorithm described in
+// https://colab.research.google.com/drive/1hI10nq6L6ru_UFvz7-f7xQaQp0qarz_K
+bool ComputePQToneMapConstants(const gfx::ColorTransform::Options& options,
+ float& a,
+ float& b) {
+ const auto hdr_metadata = gfx::HDRMetadata::PopulateUnspecifiedWithDefaults(
+ options.src_hdr_metadata);
+ const float src_max_lum_nits =
+ hdr_metadata.max_content_light_level > 0
+ ? hdr_metadata.max_content_light_level
+ : hdr_metadata.color_volume_metadata.luminance_max;
+ const float src_max_lum_relative =
+ src_max_lum_nits / options.sdr_max_luminance_nits;
+
+ if (src_max_lum_relative > options.dst_max_luminance_relative) {
+ a = options.dst_max_luminance_relative /
+ (src_max_lum_relative * src_max_lum_relative);
+ b = 1.f / options.dst_max_luminance_relative;
+ return true;
+ }
+ a = 0;
+ b = 0;
+ return false;
}
-Transform GetRangeAdjustMatrix(const gfx::ColorSpace& color_space,
- int bit_depth) {
- skia::Matrix44 range_adjust_matrix;
- color_space.GetRangeAdjustMatrix(bit_depth, &range_adjust_matrix);
- return Transform(range_adjust_matrix);
-}
-
-Transform GetPrimaryTransform(const gfx::ColorSpace& color_space) {
- skia::Matrix44 primary_matrix;
- color_space.GetPrimaryMatrix(&primary_matrix);
- return Transform(primary_matrix);
+void ComputeHLGToneMapConstants(const gfx::ColorTransform::Options& options,
+ float& gamma_minus_one) {
+ const float dst_max_luminance_nits =
+ options.sdr_max_luminance_nits * options.dst_max_luminance_relative;
+ gamma_minus_one =
+ 1.2f + 0.42f * logf(dst_max_luminance_nits / 1000.f) / logf(10.f) - 1.f;
}
} // namespace
@@ -192,13 +208,6 @@
// Return true if this is a null transform.
virtual bool IsNull() { return false; }
virtual void Transform(ColorTransform::TriStim* color, size_t num) const = 0;
- // In the shader, |hdr| will appear before |src|, so any helper functions that
- // are created should be put in |hdr|. Any helper functions should have
- // |step_index| included in the function name, to ensure that there are no
- // naming conflicts.
- virtual void AppendShaderSource(std::stringstream* hdr,
- std::stringstream* src,
- size_t step_index) const = 0;
virtual void AppendSkShaderSource(std::stringstream* src) const = 0;
};
@@ -217,8 +226,7 @@
step->Transform(colors, num);
}
}
- std::string GetShaderSource() const override;
- std::string GetSkShaderSource() const override;
+ sk_sp<SkRuntimeEffect> GetSkRuntimeEffect() const override;
bool IsIdentity() const override { return steps_.empty(); }
size_t NumberOfStepsForTesting() const override { return steps_.size(); }
@@ -238,82 +246,59 @@
ColorTransformNull* GetNull() override { return this; }
bool IsNull() override { return true; }
void Transform(ColorTransform::TriStim* color, size_t num) const override {}
- void AppendShaderSource(std::stringstream* hdr,
- std::stringstream* src,
- size_t step_index) const override {}
void AppendSkShaderSource(std::stringstream* src) const override {}
};
class ColorTransformMatrix : public ColorTransformStep {
public:
- explicit ColorTransformMatrix(const class Transform& matrix)
- : matrix_(matrix) {}
+ explicit ColorTransformMatrix(const SkM44& matrix) : matrix_(matrix) {}
ColorTransformMatrix* GetMatrix() override { return this; }
bool Join(ColorTransformStep* next_untyped) override {
ColorTransformMatrix* next = next_untyped->GetMatrix();
if (!next)
return false;
- class Transform tmp = next->matrix_;
- tmp *= matrix_;
- matrix_ = tmp;
+ matrix_.postConcat(next->matrix_);
return true;
}
- bool IsNull() override {
- return SkMatrixIsApproximatelyIdentity(matrix_.matrix());
- }
+ bool IsNull() override { return SkM44IsApproximatelyIdentity(matrix_); }
void Transform(ColorTransform::TriStim* colors, size_t num) const override {
- for (size_t i = 0; i < num; i++)
- matrix_.TransformPoint(colors + i);
- }
-
- void AppendShaderSource(std::stringstream* hdr,
- std::stringstream* src,
- size_t step_index) const override {
- const skia::Matrix44& m = matrix_.matrix();
- *src << " color = mat3(";
- *src << m.get(0, 0) << ", " << m.get(1, 0) << ", " << m.get(2, 0) << ",";
- *src << endl;
- *src << " ";
- *src << m.get(0, 1) << ", " << m.get(1, 1) << ", " << m.get(2, 1) << ",";
- *src << endl;
- *src << " ";
- *src << m.get(0, 2) << ", " << m.get(1, 2) << ", " << m.get(2, 2) << ")";
- *src << " * color;" << endl;
-
- // Only print the translational component if it isn't the identity.
- if (m.get(0, 3) != 0.f || m.get(1, 3) != 0.f || m.get(2, 3) != 0.f) {
- *src << " color += vec3(";
- *src << m.get(0, 3) << ", " << m.get(1, 3) << ", " << m.get(2, 3);
- *src << ");" << endl;
+ for (size_t i = 0; i < num; i++) {
+ auto& color = colors[i];
+ SkV4 mapped = matrix_.map(color.x(), color.y(), color.z(), 1);
+ color.SetPoint(mapped.x, mapped.y, mapped.z);
}
}
void AppendSkShaderSource(std::stringstream* src) const override {
- const skia::Matrix44& m = matrix_.matrix();
*src << " color = half4x4(";
- *src << m.get(0, 0) << ", " << m.get(1, 0) << ", " << m.get(2, 0) << ", 0,";
+ *src << matrix_.rc(0, 0) << ", " << matrix_.rc(1, 0) << ", "
+ << matrix_.rc(2, 0) << ", 0,";
*src << endl;
*src << " ";
- *src << m.get(0, 1) << ", " << m.get(1, 1) << ", " << m.get(2, 1) << ", 0,";
+ *src << matrix_.rc(0, 1) << ", " << matrix_.rc(1, 1) << ", "
+ << matrix_.rc(2, 1) << ", 0,";
*src << endl;
*src << " ";
- *src << m.get(0, 2) << ", " << m.get(1, 2) << ", " << m.get(2, 2) << ", 0,";
+ *src << matrix_.rc(0, 2) << ", " << matrix_.rc(1, 2) << ", "
+ << matrix_.rc(2, 2) << ", 0,";
*src << endl;
*src << "0, 0, 0, 1)";
*src << " * color;" << endl;
// Only print the translational component if it isn't the identity.
- if (m.get(0, 3) != 0.f || m.get(1, 3) != 0.f || m.get(2, 3) != 0.f) {
+ if (matrix_.rc(0, 3) != 0.f || matrix_.rc(1, 3) != 0.f ||
+ matrix_.rc(2, 3) != 0.f) {
*src << " color += half4(";
- *src << m.get(0, 3) << ", " << m.get(1, 3) << ", " << m.get(2, 3);
+ *src << matrix_.rc(0, 3) << ", " << matrix_.rc(1, 3) << ", "
+ << matrix_.rc(2, 3);
*src << ", 0);" << endl;
}
}
private:
- class Transform matrix_;
+ class SkM44 matrix_;
};
class ColorTransformPerChannelTransferFn : public ColorTransformStep {
@@ -336,27 +321,6 @@
}
}
- void AppendShaderSource(std::stringstream* hdr,
- std::stringstream* src,
- size_t step_index) const override {
- *hdr << "float TransferFn" << step_index << "(float v) {" << endl;
- AppendTransferShaderSource(hdr, true /* is_glsl */);
- *hdr << " return v;" << endl;
- *hdr << "}" << endl;
- if (extended_) {
- *src << " color.r = sign(color.r) * TransferFn" << step_index
- << "(abs(color.r));" << endl;
- *src << " color.g = sign(color.g) * TransferFn" << step_index
- << "(abs(color.g));" << endl;
- *src << " color.b = sign(color.b) * TransferFn" << step_index
- << "(abs(color.b));" << endl;
- } else {
- *src << " color.r = TransferFn" << step_index << "(color.r);" << endl;
- *src << " color.g = TransferFn" << step_index << "(color.g);" << endl;
- *src << " color.b = TransferFn" << step_index << "(color.b);" << endl;
- }
- }
-
void AppendSkShaderSource(std::stringstream* src) const override {
if (extended_) {
*src << "{ half v = abs(color.r);" << endl;
@@ -385,7 +349,7 @@
virtual void AppendTransferShaderSource(std::stringstream* src,
bool is_glsl) const = 0;
- protected:
+ private:
// True if the transfer function is extended to be defined for all real
// values by point symmetry.
bool extended_ = false;
@@ -512,8 +476,7 @@
ColorTransformSkTransferFn* next = next_untyped->GetSkTransferFn();
if (!next)
return false;
- if (!extended_ && !next->extended_ &&
- SkTransferFnsApproximatelyCancel(fn_, next->fn_)) {
+ if (SkTransferFnsApproximatelyCancel(fn_, next->fn_)) {
// Set to be the identity.
fn_.a = 1;
fn_.b = 0;
@@ -651,8 +614,8 @@
public:
explicit ColorTransformHLGToLinear(float sdr_white_level)
: ColorTransformPerChannelTransferFn(false),
- sdr_scale_factor_(gfx::ColorSpace::kDefaultSDRWhiteLevel /
- sdr_white_level) {}
+ sdr_scale_factor_(ColorSpace::kDefaultSDRWhiteLevel / sdr_white_level) {
+ }
// ColorTransformPerChannelTransferFn implementation:
float Evaluate(float v) const override {
@@ -898,38 +861,91 @@
YUV[i] = ColorTransform::TriStim(R_Y + Y, Y, B_Y + Y);
}
}
- void AppendShaderSource(std::stringstream* hdr,
- std::stringstream* src,
- size_t step_index) const override {
- *hdr << "vec3 BT2020_YUV_to_RYB_Step" << step_index << "(vec3 color) {"
- << endl;
- *hdr << " float Y = color.x;" << endl;
- *hdr << " float U = color.y - 0.5;" << endl;
- *hdr << " float V = color.z - 0.5;" << endl;
- *hdr << " float B_Y = 0.0;" << endl;
- *hdr << " float R_Y = 0.0;" << endl;
- *hdr << " if (U <= 0.0) {" << endl;
- *hdr << " B_Y = U * (-2.0 * -0.9702);" << endl;
- *hdr << " } else {" << endl;
- *hdr << " B_Y = U * (2.0 * 0.7910);" << endl;
- *hdr << " }" << endl;
- *hdr << " if (V <= 0.0) {" << endl;
- *hdr << " R_Y = V * (-2.0 * -0.8591);" << endl;
- *hdr << " } else {" << endl;
- *hdr << " R_Y = V * (2.0 * 0.4969);" << endl;
- *hdr << " }" << endl;
- *hdr << " return vec3(R_Y + Y, Y, B_Y + Y);" << endl;
- *hdr << "}" << endl;
-
- *src << " color.rgb = BT2020_YUV_to_RYB_Step" << step_index
- << "(color.rgb);" << endl;
- }
void AppendSkShaderSource(std::stringstream* src) const override {
NOTREACHED();
}
};
+// Apply the HLG OOTF for a specified maximum luminance.
+class ColorTransformHLGOOTF : public ColorTransformStep {
+ public:
+ explicit ColorTransformHLGOOTF(float gamma_minus_one,
+ float dst_max_luminance_relative)
+ : gamma_minus_one_(gamma_minus_one),
+ dst_max_luminance_relative_(dst_max_luminance_relative) {}
+
+ // The luminance vector in linear space.
+ static constexpr float kLr = 0.2627;
+ static constexpr float kLg = 0.6780;
+ static constexpr float kLb = 0.0593;
+
+ // ColorTransformStep implementation:
+ void Transform(ColorTransform::TriStim* color, size_t num) const override {
+ for (size_t i = 0; i < num; i++) {
+ float L = kLr * color[i].x() + kLg * color[i].y() + kLb * color[i].z();
+ if (L > 0.f) {
+ color[i].Scale(powf(L, gamma_minus_one_));
+ // Scale the result to the full HDR range.
+ color[i].Scale(dst_max_luminance_relative_);
+ }
+ }
+ }
+ void AppendSkShaderSource(std::stringstream* src) const override {
+ *src << "{\n"
+ << " half4 luma_vec = half4(" << kLr << ", " << kLg << ", " << kLb
+ << ", 0.0);\n"
+ << " half L = dot(color, luma_vec);\n"
+ << " if (L > 0.0) {\n"
+ << " color.rgb *= pow(L, hlg_ootf_gamma_minus_one);\n"
+ << " color.rgb *= hlg_dst_max_luminance_relative;\n"
+ << " }\n"
+ << "}\n";
+ }
+
+ private:
+ // The gamma parameter for the power function specified in Rec 2100.
+ const float gamma_minus_one_;
+ const float dst_max_luminance_relative_;
+};
+
+// Scale the color such that the luminance `input_max_value` maps to
+// `output_max_value`.
+class ColorTransformToneMapInRec2020Linear : public ColorTransformStep {
+ public:
+ ColorTransformToneMapInRec2020Linear(float a, float b) : a_(a), b_(b) {}
+
+ // The luminance vector in linear space.
+ static constexpr float kLr = 0.2627;
+ static constexpr float kLg = 0.6780;
+ static constexpr float kLb = 0.0593;
+
+ // ColorTransformStep implementation:
+ void Transform(ColorTransform::TriStim* color, size_t num) const override {
+ for (size_t i = 0; i < num; i++) {
+ float L = kLr * color[i].x() + kLg * color[i].y() + kLb * color[i].z();
+ if (L > 0.f)
+ color[i].Scale((1.f + a_ * L) / (1.f + b_ * L));
+ }
+ }
+ void AppendSkShaderSource(std::stringstream* src) const override {
+ *src << "{\n"
+ << " half4 luma_vec = half4(" << kLr << ", " << kLg << ", " << kLb
+ << ", 0.0);\n"
+ << " half L = dot(color, luma_vec);\n"
+ << " if (L > 0.0) {\n"
+ << " color.rgb *= (1.0 + pq_tonemap_a *L) / \n"
+ << " (1.0 + pq_tonemap_b *L);\n"
+ << " }\n"
+ << "}\n";
+ }
+
+ private:
+ // Constants derived from `input_max_value` and `output_max_value`.
+ const float a_;
+ const float b_;
+};
+
void ColorTransformInternal::AppendColorSpaceToColorSpaceTransform(
const ColorSpace& src,
const ColorSpace& dst,
@@ -940,7 +956,7 @@
src.GetMatrixID() == ColorSpace::MatrixID::GBR ||
src.GetMatrixID() == ColorSpace::MatrixID::YCOCG;
auto src_range_adjust_matrix = std::make_unique<ColorTransformMatrix>(
- GetRangeAdjustMatrix(src, options.src_bit_depth));
+ src.GetRangeAdjustMatrix(options.src_bit_depth));
if (!src_matrix_is_identity_or_ycgco)
steps_.push_back(std::move(src_range_adjust_matrix));
@@ -950,7 +966,7 @@
steps_.push_back(std::make_unique<ColorTransformFromBT2020CL>());
} else {
steps_.push_back(std::make_unique<ColorTransformMatrix>(
- Invert(GetTransferMatrix(src, options.src_bit_depth))));
+ Invert(src.GetTransferMatrix(options.src_bit_depth))));
}
if (src_matrix_is_identity_or_ycgco)
@@ -962,69 +978,119 @@
if (!dst.IsValid())
return;
- skcms_TransferFunction src_to_linear_fn;
- if (src.GetTransferFunction(&src_to_linear_fn)) {
- steps_.push_back(std::make_unique<ColorTransformSkTransferFn>(
- src_to_linear_fn, src.HasExtendedSkTransferFn()));
- } else if (src.GetTransferID() == ColorSpace::TransferID::ARIB_STD_B67) {
- float sdr_white_level = 0.f;
- src.GetSDRWhiteLevel(&sdr_white_level);
- steps_.push_back(
- std::make_unique<ColorTransformHLGToLinear>(sdr_white_level));
- } else if (src.GetTransferID() == ColorSpace::TransferID::SMPTEST2084) {
- float sdr_white_level = 0.f;
- src.GetSDRWhiteLevel(&sdr_white_level);
- steps_.push_back(
- std::make_unique<ColorTransformPQToLinear>(sdr_white_level));
- } else if (src.GetTransferID() == ColorSpace::TransferID::PIECEWISE_HDR) {
- skcms_TransferFunction fn;
- float p, q, r;
- ColorTransformPiecewiseHDR::GetParams(src, &fn, &p, &q, &r);
- steps_.push_back(std::make_unique<ColorTransformPiecewiseHDR>(fn, p, q, r));
- } else {
- steps_.push_back(
- std::make_unique<ColorTransformToLinear>(src.GetTransferID()));
+ switch (src.GetTransferID()) {
+ case ColorSpace::TransferID::HLG:
+ if (options.tone_map_pq_and_hlg_to_dst) {
+ // Convert to linear with a maximum value of 1.
+ steps_.push_back(std::make_unique<ColorTransformHLGToLinear>(
+ 12.f * ColorSpace::kDefaultSDRWhiteLevel));
+ } else {
+ steps_.push_back(std::make_unique<ColorTransformHLGToLinear>(
+ options.sdr_max_luminance_nits));
+ }
+ break;
+ case ColorSpace::TransferID::PQ:
+ steps_.push_back(std::make_unique<ColorTransformPQToLinear>(
+ options.sdr_max_luminance_nits));
+ break;
+ case ColorSpace::TransferID::PIECEWISE_HDR: {
+ skcms_TransferFunction fn;
+ float p, q, r;
+ ColorTransformPiecewiseHDR::GetParams(src, &fn, &p, &q, &r);
+ steps_.push_back(
+ std::make_unique<ColorTransformPiecewiseHDR>(fn, p, q, r));
+ break;
+ }
+ default: {
+ skcms_TransferFunction src_to_linear_fn;
+ if (src.GetTransferFunction(&src_to_linear_fn,
+ options.sdr_max_luminance_nits)) {
+ steps_.push_back(std::make_unique<ColorTransformSkTransferFn>(
+ src_to_linear_fn, src.HasExtendedSkTransferFn()));
+ } else {
+ steps_.push_back(
+ std::make_unique<ColorTransformToLinear>(src.GetTransferID()));
+ }
+ }
}
if (src.GetMatrixID() == ColorSpace::MatrixID::BT2020_CL) {
// BT2020 CL is a special case.
steps_.push_back(std::make_unique<ColorTransformMatrix>(
- Invert(GetTransferMatrix(src, options.src_bit_depth))));
+ Invert(src.GetTransferMatrix(options.src_bit_depth))));
}
steps_.push_back(
- std::make_unique<ColorTransformMatrix>(GetPrimaryTransform(src)));
+ std::make_unique<ColorTransformMatrix>(src.GetPrimaryMatrix()));
+
+ // Perform tone mapping in a linear space
+ if (options.tone_map_pq_and_hlg_to_dst) {
+ switch (src.GetTransferID()) {
+ case ColorSpace::TransferID::HLG: {
+ // Apply the HLG OOTF for the specified maximum luminance.
+ float gamma_minus_one = 0.f;
+ ComputeHLGToneMapConstants(options, gamma_minus_one);
+ steps_.push_back(std::make_unique<ColorTransformHLGOOTF>(
+ gamma_minus_one, options.dst_max_luminance_relative));
+ break;
+ }
+ case ColorSpace::TransferID::PQ: {
+ float a = 0.f;
+ float b = 0.f;
+ ComputePQToneMapConstants(options, a, b);
+ const ColorSpace rec2020_linear(
+ ColorSpace::PrimaryID::BT2020, ColorSpace::TransferID::LINEAR,
+ ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL);
+ steps_.push_back(std::make_unique<ColorTransformMatrix>(
+ Invert(rec2020_linear.GetPrimaryMatrix())));
+ steps_.push_back(
+ std::make_unique<ColorTransformToneMapInRec2020Linear>(a, b));
+ steps_.push_back(std::make_unique<ColorTransformMatrix>(
+ rec2020_linear.GetPrimaryMatrix()));
+ break;
+ }
+ default:
+ break;
+ }
+ }
steps_.push_back(
- std::make_unique<ColorTransformMatrix>(Invert(GetPrimaryTransform(dst))));
+ std::make_unique<ColorTransformMatrix>(Invert(dst.GetPrimaryMatrix())));
if (dst.GetMatrixID() == ColorSpace::MatrixID::BT2020_CL) {
// BT2020 CL is a special case.
steps_.push_back(std::make_unique<ColorTransformMatrix>(
- GetTransferMatrix(dst, options.dst_bit_depth)));
+ dst.GetTransferMatrix(options.dst_bit_depth)));
}
- skcms_TransferFunction dst_from_linear_fn;
- if (dst.GetInverseTransferFunction(&dst_from_linear_fn)) {
- steps_.push_back(std::make_unique<ColorTransformSkTransferFn>(
- dst_from_linear_fn, dst.HasExtendedSkTransferFn()));
- } else if (dst.GetTransferID() == ColorSpace::TransferID::ARIB_STD_B67) {
- float sdr_white_level = 0.f;
- dst.GetSDRWhiteLevel(&sdr_white_level);
- steps_.push_back(
- std::make_unique<ColorTransformHLGFromLinear>(sdr_white_level));
- } else if (dst.GetTransferID() == ColorSpace::TransferID::SMPTEST2084) {
- float sdr_white_level = 0.f;
- dst.GetSDRWhiteLevel(&sdr_white_level);
- steps_.push_back(
- std::make_unique<ColorTransformPQFromLinear>(sdr_white_level));
- } else if (dst.GetTransferID() == ColorSpace::TransferID::PIECEWISE_HDR) {
- skcms_TransferFunction fn;
- float p, q, r;
- ColorTransformPiecewiseHDR::GetParams(dst, &fn, &p, &q, &r);
- ColorTransformPiecewiseHDR::InvertParams(&fn, &p, &q, &r);
- steps_.push_back(std::make_unique<ColorTransformPiecewiseHDR>(fn, p, q, r));
- } else {
- steps_.push_back(
- std::make_unique<ColorTransformFromLinear>(dst.GetTransferID()));
+ switch (dst.GetTransferID()) {
+ case ColorSpace::TransferID::HLG:
+ steps_.push_back(std::make_unique<ColorTransformHLGFromLinear>(
+ options.sdr_max_luminance_nits));
+ break;
+ case ColorSpace::TransferID::PQ:
+ steps_.push_back(std::make_unique<ColorTransformPQFromLinear>(
+ options.sdr_max_luminance_nits));
+ break;
+ case ColorSpace::TransferID::PIECEWISE_HDR: {
+ skcms_TransferFunction fn;
+ float p, q, r;
+ ColorTransformPiecewiseHDR::GetParams(dst, &fn, &p, &q, &r);
+ ColorTransformPiecewiseHDR::InvertParams(&fn, &p, &q, &r);
+ steps_.push_back(
+ std::make_unique<ColorTransformPiecewiseHDR>(fn, p, q, r));
+ break;
+ }
+ default: {
+ skcms_TransferFunction dst_from_linear_fn;
+ if (dst.GetInverseTransferFunction(&dst_from_linear_fn,
+ options.sdr_max_luminance_nits)) {
+ steps_.push_back(std::make_unique<ColorTransformSkTransferFn>(
+ dst_from_linear_fn, dst.HasExtendedSkTransferFn()));
+ } else {
+ steps_.push_back(
+ std::make_unique<ColorTransformFromLinear>(dst.GetTransferID()));
+ }
+ break;
+ }
}
// ITU-T H.273: If MatrixCoefficients is equal to 0 (Identity) or 8 (YCgCo),
@@ -1033,7 +1099,7 @@
dst.GetMatrixID() == ColorSpace::MatrixID::GBR ||
dst.GetMatrixID() == ColorSpace::MatrixID::YCOCG;
auto dst_range_adjust_matrix = std::make_unique<ColorTransformMatrix>(
- Invert(GetRangeAdjustMatrix(dst, options.dst_bit_depth)));
+ Invert(dst.GetRangeAdjustMatrix(options.dst_bit_depth)));
if (dst_matrix_is_identity_or_ycgco)
steps_.push_back(std::move(dst_range_adjust_matrix));
@@ -1042,7 +1108,7 @@
NOTREACHED();
} else {
steps_.push_back(std::make_unique<ColorTransformMatrix>(
- GetTransferMatrix(dst, options.dst_bit_depth)));
+ dst.GetTransferMatrix(options.dst_bit_depth)));
}
if (!dst_matrix_is_identity_or_ycgco)
@@ -1062,26 +1128,73 @@
Simplify();
}
-std::string ColorTransformInternal::GetShaderSource() const {
- std::stringstream hdr;
+sk_sp<SkRuntimeEffect> ColorTransformInternal::GetSkRuntimeEffect() const {
std::stringstream src;
- InitStringStream(&hdr);
InitStringStream(&src);
- src << "vec3 DoColorConversion(vec3 color) {" << endl;
- size_t step_index = 0;
- for (const auto& step : steps_)
- step->AppendShaderSource(&hdr, &src, step_index++);
- src << " return color;" << endl;
- src << "}" << endl;
- return hdr.str() + src.str();
-}
-std::string ColorTransformInternal::GetSkShaderSource() const {
- std::stringstream src;
- InitStringStream(&src);
+ src << "uniform half offset;\n"
+ << "uniform half multiplier;\n"
+ << "uniform half pq_tonemap_a;\n"
+ << "uniform half pq_tonemap_b;\n"
+ << "uniform half hlg_ootf_gamma_minus_one;\n"
+ << "uniform half hlg_dst_max_luminance_relative;\n"
+ << "\n"
+ << "half4 main(half4 color) {\n"
+ << " // Un-premultiply alpha\n"
+ << " if (color.a > 0)\n"
+ << " color.rgb /= color.a;\n"
+ << "\n"
+ << " color.rgb -= offset;\n"
+ << " color.rgb *= multiplier;\n";
+
for (const auto& step : steps_)
step->AppendSkShaderSource(&src);
- return src.str();
+
+ src << " // premultiply alpha\n"
+ " color.rgb *= color.a;\n"
+ " return color;\n"
+ "}\n";
+
+ auto sksl_source = src.str();
+ auto result = SkRuntimeEffect::MakeForColorFilter(
+ SkString(sksl_source.c_str(), sksl_source.size()),
+ /*options=*/{});
+ DCHECK(result.effect) << '\n'
+ << result.errorText.c_str() << "\n\nShader Source:\n"
+ << sksl_source;
+ return result.effect;
+}
+
+struct SkShaderUniforms {
+ float offset = 0.f;
+ float multiplier = 0.f;
+ float pq_tonemap_a = 1.f;
+ float pq_tonemap_b = 1.f;
+ float hlg_ootf_gamma_minus_one = 0.f;
+ float hlg_dst_max_luminance_relative = 1.0f;
+};
+
+// static
+sk_sp<SkData> ColorTransform::GetSkShaderUniforms(const ColorSpace& src,
+ const ColorSpace& dst,
+ float offset,
+ float multiplier,
+ const Options& options) {
+ SkShaderUniforms data;
+ data.offset = offset;
+ data.multiplier = multiplier;
+ data.hlg_dst_max_luminance_relative = options.dst_max_luminance_relative;
+ switch (src.GetTransferID()) {
+ case ColorSpace::TransferID::PQ:
+ ComputePQToneMapConstants(options, data.pq_tonemap_a, data.pq_tonemap_b);
+ break;
+ case ColorSpace::TransferID::HLG:
+ ComputeHLGToneMapConstants(options, data.hlg_ootf_gamma_minus_one);
+ break;
+ default:
+ break;
+ }
+ return SkData::MakeWithCopy(&data, sizeof(data));
}
ColorTransformInternal::~ColorTransformInternal() {}
diff --git a/ui/gfx/color_transform.h b/ui/gfx/color_transform.h
index 62bc935..88c4b4e 100644
--- a/ui/gfx/color_transform.h
+++ b/ui/gfx/color_transform.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,14 +8,17 @@
#include <memory>
#include <string>
-#include "base/macros.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/skia/include/core/SkData.h"
+#include "third_party/skia/include/effects/SkRuntimeEffect.h"
#include "ui/gfx/color_space.h"
+#include "ui/gfx/color_space_export.h"
#include "ui/gfx/geometry/point3_f.h"
-#include "ui/gfx/gfx_export.h"
+#include "ui/gfx/hdr_metadata.h"
namespace gfx {
-class GFX_EXPORT ColorTransform {
+class COLOR_SPACE_EXPORT ColorTransform {
public:
struct Options {
// Used in testing to verify that optimizations have no effect.
@@ -24,6 +27,24 @@
// Used to adjust the transfer and range adjust matrices.
uint32_t src_bit_depth = kDefaultBitDepth;
uint32_t dst_bit_depth = kDefaultBitDepth;
+
+ // If set to true, then map PQ and HLG imputs such that their maximum
+ // luminance will be `dst_max_luminance_relative`.
+ bool tone_map_pq_and_hlg_to_dst = false;
+
+ // Used for tone mapping and for interpreting color spaces whose
+ // definition depends on an SDR white point.
+ // TODO(https://crbug.com/1286082): Use this value in the transform.
+ float sdr_max_luminance_nits = ColorSpace::kDefaultSDRWhiteLevel;
+
+ // Used for tone mapping PQ sources.
+ absl::optional<gfx::HDRMetadata> src_hdr_metadata;
+
+ // The maximum luminance value for the destination, as a multiple of
+ // `sdr_max_luminance_nits` (so this is 1 for SDR displays).
+ // TODO(https://crbug.com/1286076): Use this value for transforming
+ // PQ and HLG content.
+ float dst_max_luminance_relative = 1.f;
};
// TriStimulus is a color coordinate in any color space.
@@ -42,13 +63,15 @@
// Perform transformation of colors, |colors| is both input and output.
virtual void Transform(TriStim* colors, size_t num) const = 0;
- // Return GLSL shader source that defines a function DoColorConversion that
- // converts a vec3 according to this transform.
- virtual std::string GetShaderSource() const = 0;
+ // Return an SkRuntimeEffect to perform this transform.
+ virtual sk_sp<SkRuntimeEffect> GetSkRuntimeEffect() const = 0;
- // Return SKSL shader sources that modifies an "inout half4 color" according
- // to this transform. Input and output are non-premultiplied alpha.
- virtual std::string GetSkShaderSource() const = 0;
+ // Return the uniforms used by the above SkRuntimeEffect.
+ static sk_sp<SkData> GetSkShaderUniforms(const ColorSpace& src,
+ const ColorSpace& dst,
+ float offset,
+ float multiplier,
+ const Options& options);
// Returns true if this transform is the identity.
virtual bool IsIdentity() const = 0;
diff --git a/ui/gfx/color_transform_fuzzer.cc b/ui/gfx/color_transform_fuzzer.cc
index c3f8a93..1c4715a 100644
--- a/ui/gfx/color_transform_fuzzer.cc
+++ b/ui/gfx/color_transform_fuzzer.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/color_transform_unittest.cc b/ui/gfx/color_transform_unittest.cc
index d8fac5b..739ca14 100644
--- a/ui/gfx/color_transform_unittest.cc
+++ b/ui/gfx/color_transform_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,6 +11,7 @@
#include "ui/gfx/color_space.h"
#include "ui/gfx/color_transform.h"
#include "ui/gfx/geometry/transform.h"
+#include "ui/gfx/gfx_export.h"
#include "ui/gfx/icc_profile.h"
#include "ui/gfx/skia_color_space_util.h"
#include "ui/gfx/test/icc_profiles.h"
@@ -28,32 +29,23 @@
ColorSpace::PrimaryID::BT470BG, ColorSpace::PrimaryID::SMPTE170M,
ColorSpace::PrimaryID::SMPTE240M, ColorSpace::PrimaryID::FILM,
ColorSpace::PrimaryID::BT2020, ColorSpace::PrimaryID::SMPTEST428_1,
- ColorSpace::PrimaryID::SMPTEST431_2, ColorSpace::PrimaryID::SMPTEST432_1,
+ ColorSpace::PrimaryID::SMPTEST431_2, ColorSpace::PrimaryID::P3,
};
ColorSpace::TransferID simple_transfers[] = {
- ColorSpace::TransferID::BT709,
- ColorSpace::TransferID::GAMMA22,
- ColorSpace::TransferID::GAMMA28,
- ColorSpace::TransferID::SMPTE170M,
- ColorSpace::TransferID::SMPTE240M,
- ColorSpace::TransferID::SMPTEST428_1,
- ColorSpace::TransferID::LINEAR,
- ColorSpace::TransferID::LOG,
- ColorSpace::TransferID::LOG_SQRT,
- ColorSpace::TransferID::IEC61966_2_4,
- ColorSpace::TransferID::BT1361_ECG,
- ColorSpace::TransferID::IEC61966_2_1,
- ColorSpace::TransferID::BT2020_10,
- ColorSpace::TransferID::BT2020_12,
- ColorSpace::TransferID::SMPTEST2084,
- ColorSpace::TransferID::ARIB_STD_B67,
- ColorSpace::TransferID::IEC61966_2_1_HDR,
+ ColorSpace::TransferID::BT709, ColorSpace::TransferID::GAMMA22,
+ ColorSpace::TransferID::GAMMA28, ColorSpace::TransferID::SMPTE170M,
+ ColorSpace::TransferID::SMPTE240M, ColorSpace::TransferID::SMPTEST428_1,
+ ColorSpace::TransferID::LINEAR, ColorSpace::TransferID::LOG,
+ ColorSpace::TransferID::LOG_SQRT, ColorSpace::TransferID::IEC61966_2_4,
+ ColorSpace::TransferID::BT1361_ECG, ColorSpace::TransferID::SRGB,
+ ColorSpace::TransferID::BT2020_10, ColorSpace::TransferID::BT2020_12,
+ ColorSpace::TransferID::SRGB_HDR,
};
ColorSpace::TransferID extended_transfers[] = {
ColorSpace::TransferID::LINEAR_HDR,
- ColorSpace::TransferID::IEC61966_2_1_HDR,
+ ColorSpace::TransferID::SRGB_HDR,
};
ColorSpace::MatrixID all_matrices[] = {
@@ -125,8 +117,7 @@
}
TEST(SimpleColorSpace, YCOCGLimitedToSRGB) {
- ColorSpace ycocg(ColorSpace::PrimaryID::BT709,
- ColorSpace::TransferID::IEC61966_2_1,
+ ColorSpace ycocg(ColorSpace::PrimaryID::BT709, ColorSpace::TransferID::SRGB,
ColorSpace::MatrixID::YCOCG, ColorSpace::RangeID::LIMITED);
ColorSpace sRGB = ColorSpace::CreateSRGB();
std::unique_ptr<ColorTransform> t(
@@ -175,7 +166,7 @@
ColorSpace bt709(primary, ColorSpace::TransferID::BT709, matrix, range);
// IEC61966_2_1 has the sRGB gamma of 2.4 (with some adjustments)
- ColorSpace srgb(primary, ColorSpace::TransferID::IEC61966_2_1, matrix, range);
+ ColorSpace srgb(primary, ColorSpace::TransferID::SRGB, matrix, range);
// gamma28 is a simple exponential
ColorSpace gamma28(primary, ColorSpace::TransferID::GAMMA28, matrix, range);
@@ -449,103 +440,25 @@
EXPECT_EQ(t2->NumberOfStepsForTesting(), 0u);
}
-// This tests to make sure that we don't emit "pow" parts of a
-// transfer function unless necessary.
-TEST(SimpleColorSpace, ShaderSourceTrFnOptimizations) {
- skcms_Matrix3x3 primaries;
- gfx::ColorSpace::CreateSRGB().GetPrimaryMatrix(&primaries);
-
- skcms_TransferFunction fn_no_pow = {
- 1.f, 2.f, 0.f, 1.f, 0.f, 0.f, 0.f,
- };
- skcms_TransferFunction fn_yes_pow = {
- 2.f, 2.f, 0.f, 1.f, 0.f, 0.f, 0.f,
- };
- gfx::ColorSpace src;
- gfx::ColorSpace dst = gfx::ColorSpace::CreateXYZD50();
- std::string shader_string;
-
- src = gfx::ColorSpace::CreateCustom(primaries, fn_no_pow);
- shader_string =
- ColorTransform::NewColorTransform(src, dst)->GetShaderSource();
- EXPECT_EQ(shader_string.find("pow("), std::string::npos);
-
- src = gfx::ColorSpace::CreateCustom(primaries, fn_yes_pow);
- shader_string =
- ColorTransform::NewColorTransform(src, dst)->GetShaderSource();
- EXPECT_NE(shader_string.find("pow("), std::string::npos);
-}
-
-// Note: This is not actually "testing" anything -- the goal of this test is to
-// to make reviewing shader code simpler by giving an example of the resulting
-// shader source. This should be updated whenever shader generation is updated.
-// This test produces slightly different results on Android.
-TEST(SimpleColorSpace, SampleShaderSource) {
- ColorSpace bt709 = ColorSpace::CreateREC709();
- ColorSpace output(ColorSpace::PrimaryID::BT2020,
- ColorSpace::TransferID::GAMMA28);
- std::string source =
- ColorTransform::NewColorTransform(bt709, output)->GetShaderSource();
- std::string expected =
- "float TransferFn1(float v) {\n"
- " if (v < 4.04499359e-02)\n"
- " v = 7.73993805e-02 * v;\n"
- " else\n"
- " v = pow(9.47867334e-01 * v + 5.21326549e-02, 2.40000010e+00);\n"
- " return v;\n"
- "}\n"
- "float TransferFn3(float v) {\n"
- " if (v < 0.00000000e+00)\n"
- " v = 0.00000000e+00 * v;\n"
- " else\n"
- " v = pow(v, 3.57142866e-01);\n"
- " return v;\n"
- "}\n"
- "vec3 DoColorConversion(vec3 color) {\n"
- " color = mat3(1.16438353e+00, 1.16438353e+00, 1.16438353e+00,\n"
- " -2.28029018e-09, -2.13248596e-01, 2.11240172e+00,\n"
- " 1.79274118e+00, -5.32909274e-01, -5.96049432e-10) "
- "* color;\n"
- " color += vec3(-9.69429970e-01, 3.00019622e-01, -1.12926030e+00);\n"
- " color.r = TransferFn1(color.r);\n"
- " color.g = TransferFn1(color.g);\n"
- " color.b = TransferFn1(color.b);\n"
- " color = mat3(6.27404153e-01, 6.90974146e-02, 1.63914431e-02,\n"
- " 3.29283088e-01, 9.19540644e-01, 8.80132765e-02,\n"
- " 4.33131084e-02, 1.13623096e-02, 8.95595253e-01) "
- "* color;\n"
- " color.r = TransferFn3(color.r);\n"
- " color.g = TransferFn3(color.g);\n"
- " color.b = TransferFn3(color.b);\n"
- " return color;\n"
- "}\n";
- EXPECT_EQ(source, expected);
-}
-
// Checks that the generated SkSL fragment shaders can be parsed by
// SkSL::Compiler.
TEST(SimpleColorSpace, CanParseSkShaderSource) {
std::vector<ColorSpace> common_color_spaces = {
ColorSpace::CreateSRGB(), ColorSpace::CreateDisplayP3D65(),
- ColorSpace::CreateExtendedSRGB(), ColorSpace::CreateSCRGBLinear(),
+ ColorSpace::CreateExtendedSRGB(), ColorSpace::CreateSRGBLinear(),
ColorSpace::CreateJpeg(), ColorSpace::CreateREC601(),
ColorSpace::CreateREC709()};
for (const auto& src : common_color_spaces) {
for (const auto& dst : common_color_spaces) {
auto transform = ColorTransform::NewColorTransform(src, dst);
- std::string source = "half4 main(half4 color) {\n" +
- transform->GetSkShaderSource() + " return color; }";
- SkRuntimeEffect::Result result = SkRuntimeEffect::MakeForColorFilter(
- SkString(source.c_str(), source.length()), /*options=*/{});
- EXPECT_NE(result.effect, nullptr);
- EXPECT_STREQ(result.errorText.c_str(), "");
+ EXPECT_NE(transform->GetSkRuntimeEffect(), nullptr);
}
}
}
class TransferTest : public testing::TestWithParam<ColorSpace::TransferID> {};
-TEST_P(TransferTest, basicTest) {
+TEST_P(TransferTest, BasicTest) {
gfx::ColorSpace space_with_transfer(ColorSpace::PrimaryID::BT709, GetParam(),
ColorSpace::MatrixID::RGB,
ColorSpace::RangeID::FULL);
@@ -614,9 +527,9 @@
bool>
ColorSpaceTestData;
-class ColorSpaceTest : public testing::TestWithParam<ColorSpaceTestData> {
+class ColorSpaceTestBase : public testing::TestWithParam<ColorSpaceTestData> {
public:
- ColorSpaceTest()
+ ColorSpaceTestBase()
: color_space_(std::get<0>(GetParam()),
std::get<1>(GetParam()),
std::get<2>(GetParam()),
@@ -629,7 +542,7 @@
ColorTransform::Options options_;
};
-TEST_P(ColorSpaceTest, testNullTransform) {
+TEST_P(ColorSpaceTestBase, testNullTransform) {
std::unique_ptr<ColorTransform> t(
ColorTransform::NewColorTransform(color_space_, color_space_, options_));
ColorTransform::TriStim tristim(0.4f, 0.5f, 0.6f);
@@ -639,7 +552,7 @@
EXPECT_NEAR(tristim.z(), 0.6f, kMathEpsilon);
}
-TEST_P(ColorSpaceTest, toXYZandBack) {
+TEST_P(ColorSpaceTestBase, toXYZandBack) {
std::unique_ptr<ColorTransform> t1(ColorTransform::NewColorTransform(
color_space_, ColorSpace::CreateXYZD50(), options_));
std::unique_ptr<ColorTransform> t2(ColorTransform::NewColorTransform(
@@ -654,7 +567,7 @@
INSTANTIATE_TEST_SUITE_P(
A,
- ColorSpaceTest,
+ ColorSpaceTestBase,
testing::Combine(testing::ValuesIn(all_primaries),
testing::ValuesIn(simple_transfers),
testing::Values(ColorSpace::MatrixID::BT709),
@@ -663,7 +576,7 @@
INSTANTIATE_TEST_SUITE_P(
B,
- ColorSpaceTest,
+ ColorSpaceTestBase,
testing::Combine(testing::Values(ColorSpace::PrimaryID::BT709),
testing::ValuesIn(simple_transfers),
testing::ValuesIn(all_matrices),
@@ -672,7 +585,7 @@
INSTANTIATE_TEST_SUITE_P(
C,
- ColorSpaceTest,
+ ColorSpaceTestBase,
testing::Combine(testing::ValuesIn(all_primaries),
testing::Values(ColorSpace::TransferID::BT709),
testing::ValuesIn(all_matrices),
@@ -720,17 +633,12 @@
};
float nits[] = {80.f, 100.f, 200.f};
- for (size_t i = 0; i < 4; ++i) {
+ for (size_t i = 0; i < 3; ++i) {
// We'll set the SDR white level to the values in |nits| and also the
// default.
- ColorSpace hdr10 =
- i < 3 ? ColorSpace::CreateHDR10(nits[i]) : ColorSpace::CreateHDR10();
- float white_level = 0;
- EXPECT_TRUE(hdr10.GetSDRWhiteLevel(&white_level));
- if (i < 3)
- EXPECT_EQ(white_level, nits[i]);
- else
- EXPECT_EQ(white_level, ColorSpace::kDefaultSDRWhiteLevel);
+ const ColorSpace hdr10 = ColorSpace::CreateHDR10();
+ ColorTransform::Options options;
+ options.sdr_max_luminance_nits = nits[i];
// Transform to the same color space, but with the LINEAR_HDR transfer
// function.
@@ -738,7 +646,7 @@
ColorSpace::TransferID::LINEAR_HDR,
ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL);
std::unique_ptr<ColorTransform> xform(
- ColorTransform::NewColorTransform(hdr10, target));
+ ColorTransform::NewColorTransform(hdr10, target, options));
// Do the transform to the values in |pq_encoded_nits|.
ColorTransform::TriStim val(pq_encoded_nits[0], pq_encoded_nits[1],
@@ -768,7 +676,7 @@
// Test the inverse transform.
std::unique_ptr<ColorTransform> xform_inv(
- ColorTransform::NewColorTransform(target, hdr10));
+ ColorTransform::NewColorTransform(target, hdr10, options));
xform_inv->Transform(&val, 1);
EXPECT_NEAR(val.x(), pq_encoded_nits[0], kMathEpsilon);
EXPECT_NEAR(val.y(), pq_encoded_nits[1], kMathEpsilon);
@@ -784,20 +692,14 @@
0.5f, // 0.5 * sqrt(1.0 * 100 / 100)
0.65641f, // 0.17883277 * ln(1.0 * 200 / 100 - 0.28466892) + 0.55991073
};
- constexpr float nits[] = {80.f, 100.f, 200.f};
+ constexpr float nits[] = {203.f / 2, 203.f, 203.f * 2};
- for (size_t i = 0; i < 4; ++i) {
+ for (size_t i = 0; i < 3; ++i) {
// We'll set the SDR white level to the values in |nits| and also the
// default.
- ColorSpace hlg = i < 3
- ? ColorSpace::CreateHLG().GetWithSDRWhiteLevel(nits[i])
- : ColorSpace::CreateHLG();
- float white_level = 0;
- EXPECT_TRUE(hlg.GetSDRWhiteLevel(&white_level));
- if (i < 3)
- EXPECT_EQ(white_level, nits[i]);
- else
- EXPECT_EQ(white_level, ColorSpace::kDefaultSDRWhiteLevel);
+ const ColorSpace hlg = ColorSpace::CreateHLG();
+ ColorTransform::Options options;
+ options.sdr_max_luminance_nits = nits[i];
// Transform to the same color space, but with the LINEAR_HDR transfer
// function.
@@ -805,7 +707,7 @@
ColorSpace::TransferID::LINEAR_HDR,
ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL);
std::unique_ptr<ColorTransform> xform(
- ColorTransform::NewColorTransform(hlg, target));
+ ColorTransform::NewColorTransform(hlg, target, options));
// Do the transform to the values in |hlg_encoded_nits|.
ColorTransform::TriStim val(hlg_encoded_nits[0], hlg_encoded_nits[1],
@@ -816,7 +718,7 @@
// via a ColorSpace with the right SDR white level.
switch (i) {
case 0:
- EXPECT_NEAR(val.x(), 1.f, kMathEpsilon);
+ EXPECT_NEAR(val.x(), 1.6f, kMathEpsilon);
break;
case 1:
EXPECT_NEAR(val.y(), 1.f, kMathEpsilon);
@@ -830,13 +732,9 @@
break;
}
- // The nit ratios should be preserved by the transform.
- EXPECT_NEAR(val.y() / val.x(), nits[1] / nits[0], kMathEpsilon);
- EXPECT_NEAR(val.z() / val.x(), nits[2] / nits[0], kMathEpsilon);
-
// Test the inverse transform.
std::unique_ptr<ColorTransform> xform_inv(
- ColorTransform::NewColorTransform(target, hlg));
+ ColorTransform::NewColorTransform(target, hlg, options));
xform_inv->Transform(&val, 1);
EXPECT_NEAR(val.x(), hlg_encoded_nits[0], kMathEpsilon);
EXPECT_NEAR(val.y(), hlg_encoded_nits[1], kMathEpsilon);
diff --git a/ui/gfx/color_utils.cc b/ui/gfx/color_utils.cc
index 06aaaf8..8796a61 100644
--- a/ui/gfx/color_utils.cc
+++ b/ui/gfx/color_utils.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,17 +8,20 @@
#include <algorithm>
#include <cmath>
+#include <ostream>
+#include <vector>
#include "base/check_op.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/color_palette.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include "skia/ext/skia_utils_win.h"
#endif
@@ -55,8 +58,7 @@
}
// Assumes sRGB.
-float Linearize(float eight_bit_component) {
- const float component = eight_bit_component / 255.0f;
+float Linearize(float component) {
// The W3C link in the header uses 0.03928 here. See
// https://en.wikipedia.org/wiki/SRGB#Theory_of_the_transformation for
// discussion of why we use this value rather than that one.
@@ -64,138 +66,323 @@
: pow((component + 0.055f) / 1.055f, 2.4f);
}
-constexpr size_t kNumGoogleColors = 10;
+constexpr size_t kNumGoogleColors = 12;
constexpr SkColor kGrey[kNumGoogleColors] = {
- gfx::kGoogleGrey050, gfx::kGoogleGrey100, gfx::kGoogleGrey200,
- gfx::kGoogleGrey300, gfx::kGoogleGrey400, gfx::kGoogleGrey500,
- gfx::kGoogleGrey600, gfx::kGoogleGrey700, gfx::kGoogleGrey800,
- gfx::kGoogleGrey900,
+ SK_ColorWHITE, gfx::kGoogleGrey050, gfx::kGoogleGrey100,
+ gfx::kGoogleGrey200, gfx::kGoogleGrey300, gfx::kGoogleGrey400,
+ gfx::kGoogleGrey500, gfx::kGoogleGrey600, gfx::kGoogleGrey700,
+ gfx::kGoogleGrey800, gfx::kGoogleGrey900, gfx::kGoogleGrey900,
};
constexpr SkColor kRed[kNumGoogleColors] = {
- gfx::kGoogleRed050, gfx::kGoogleRed100, gfx::kGoogleRed200,
- gfx::kGoogleRed300, gfx::kGoogleRed400, gfx::kGoogleRed500,
- gfx::kGoogleRed600, gfx::kGoogleRed700, gfx::kGoogleRed800,
- gfx::kGoogleRed900,
+ SK_ColorWHITE, gfx::kGoogleRed050, gfx::kGoogleRed100,
+ gfx::kGoogleRed200, gfx::kGoogleRed300, gfx::kGoogleRed400,
+ gfx::kGoogleRed500, gfx::kGoogleRed600, gfx::kGoogleRed700,
+ gfx::kGoogleRed800, gfx::kGoogleRed900, gfx::kGoogleGrey900,
};
constexpr SkColor kOrange[kNumGoogleColors] = {
- gfx::kGoogleOrange050, gfx::kGoogleOrange100, gfx::kGoogleOrange200,
- gfx::kGoogleOrange300, gfx::kGoogleOrange400, gfx::kGoogleOrange500,
- gfx::kGoogleOrange600, gfx::kGoogleOrange700, gfx::kGoogleOrange800,
- gfx::kGoogleOrange900,
+ SK_ColorWHITE, gfx::kGoogleOrange050, gfx::kGoogleOrange100,
+ gfx::kGoogleOrange200, gfx::kGoogleOrange300, gfx::kGoogleOrange400,
+ gfx::kGoogleOrange500, gfx::kGoogleOrange600, gfx::kGoogleOrange700,
+ gfx::kGoogleOrange800, gfx::kGoogleOrange900, gfx::kGoogleGrey900,
};
constexpr SkColor kYellow[kNumGoogleColors] = {
- gfx::kGoogleYellow050, gfx::kGoogleYellow100, gfx::kGoogleYellow200,
- gfx::kGoogleYellow300, gfx::kGoogleYellow400, gfx::kGoogleYellow500,
- gfx::kGoogleYellow600, gfx::kGoogleYellow700, gfx::kGoogleYellow800,
- gfx::kGoogleYellow900,
+ SK_ColorWHITE, gfx::kGoogleYellow050, gfx::kGoogleYellow100,
+ gfx::kGoogleYellow200, gfx::kGoogleYellow300, gfx::kGoogleYellow400,
+ gfx::kGoogleYellow500, gfx::kGoogleYellow600, gfx::kGoogleYellow700,
+ gfx::kGoogleYellow800, gfx::kGoogleYellow900, gfx::kGoogleGrey900,
};
constexpr SkColor kGreen[kNumGoogleColors] = {
- gfx::kGoogleGreen050, gfx::kGoogleGreen100, gfx::kGoogleGreen200,
- gfx::kGoogleGreen300, gfx::kGoogleGreen400, gfx::kGoogleGreen500,
- gfx::kGoogleGreen600, gfx::kGoogleGreen700, gfx::kGoogleGreen800,
- gfx::kGoogleGreen900,
+ SK_ColorWHITE, gfx::kGoogleGreen050, gfx::kGoogleGreen100,
+ gfx::kGoogleGreen200, gfx::kGoogleGreen300, gfx::kGoogleGreen400,
+ gfx::kGoogleGreen500, gfx::kGoogleGreen600, gfx::kGoogleGreen700,
+ gfx::kGoogleGreen800, gfx::kGoogleGreen900, gfx::kGoogleGrey900,
+};
+
+constexpr SkColor kCyan[kNumGoogleColors] = {
+ SK_ColorWHITE, gfx::kGoogleCyan050, gfx::kGoogleCyan100,
+ gfx::kGoogleCyan200, gfx::kGoogleCyan300, gfx::kGoogleCyan400,
+ gfx::kGoogleCyan500, gfx::kGoogleCyan600, gfx::kGoogleCyan700,
+ gfx::kGoogleCyan800, gfx::kGoogleCyan900, gfx::kGoogleGrey900,
};
constexpr SkColor kBlue[kNumGoogleColors] = {
- gfx::kGoogleBlue050, gfx::kGoogleBlue100, gfx::kGoogleBlue200,
- gfx::kGoogleBlue300, gfx::kGoogleBlue400, gfx::kGoogleBlue500,
- gfx::kGoogleBlue600, gfx::kGoogleBlue700, gfx::kGoogleBlue800,
- gfx::kGoogleBlue900,
+ SK_ColorWHITE, gfx::kGoogleBlue050, gfx::kGoogleBlue100,
+ gfx::kGoogleBlue200, gfx::kGoogleBlue300, gfx::kGoogleBlue400,
+ gfx::kGoogleBlue500, gfx::kGoogleBlue600, gfx::kGoogleBlue700,
+ gfx::kGoogleBlue800, gfx::kGoogleBlue900, gfx::kGoogleGrey900,
};
constexpr SkColor kPurple[kNumGoogleColors] = {
- gfx::kGooglePurple050, gfx::kGooglePurple100, gfx::kGooglePurple200,
- gfx::kGooglePurple300, gfx::kGooglePurple400, gfx::kGooglePurple500,
- gfx::kGooglePurple600, gfx::kGooglePurple700, gfx::kGooglePurple800,
- gfx::kGooglePurple900,
+ SK_ColorWHITE, gfx::kGooglePurple050, gfx::kGooglePurple100,
+ gfx::kGooglePurple200, gfx::kGooglePurple300, gfx::kGooglePurple400,
+ gfx::kGooglePurple500, gfx::kGooglePurple600, gfx::kGooglePurple700,
+ gfx::kGooglePurple800, gfx::kGooglePurple900, gfx::kGoogleGrey900,
+};
+
+constexpr SkColor kMagenta[kNumGoogleColors] = {
+ SK_ColorWHITE, gfx::kGoogleMagenta050, gfx::kGoogleMagenta100,
+ gfx::kGoogleMagenta200, gfx::kGoogleMagenta300, gfx::kGoogleMagenta400,
+ gfx::kGoogleMagenta500, gfx::kGoogleMagenta600, gfx::kGoogleMagenta700,
+ gfx::kGoogleMagenta800, gfx::kGoogleMagenta900, gfx::kGoogleGrey900,
};
constexpr SkColor kPink[kNumGoogleColors] = {
- gfx::kGooglePink050, gfx::kGooglePink100, gfx::kGooglePink200,
- gfx::kGooglePink300, gfx::kGooglePink400, gfx::kGooglePink500,
- gfx::kGooglePink600, gfx::kGooglePink700, gfx::kGooglePink800,
- gfx::kGooglePink900,
+ SK_ColorWHITE, gfx::kGooglePink050, gfx::kGooglePink100,
+ gfx::kGooglePink200, gfx::kGooglePink300, gfx::kGooglePink400,
+ gfx::kGooglePink500, gfx::kGooglePink600, gfx::kGooglePink700,
+ gfx::kGooglePink800, gfx::kGooglePink900, gfx::kGoogleGrey900,
};
SkColor PickGoogleColor(const SkColor (&colors)[kNumGoogleColors],
- SkColor background_color,
- float min_contrast) {
- // For dark backgrounds we start at 500 and go down (toward brighter colors).
- constexpr size_t kDarkBackgroundStartIndex = 5;
- static_assert(kBlue[kDarkBackgroundStartIndex] == gfx::kGoogleBlue500,
- "The start index needs to match kGoogleBlue500");
- const float background_luminance = GetRelativeLuminance(background_color);
- if (IsDark(background_color)) {
- for (size_t i = kDarkBackgroundStartIndex; i > 0; --i) {
- if (GetContrastRatio(GetRelativeLuminance(colors[i]),
- background_luminance) > min_contrast) {
- return colors[i];
+ SkColor color,
+ SkColor background_color_a,
+ SkColor background_color_b,
+ float min_contrast,
+ float max_contrast_with_nearer) {
+ // Sanity checks.
+ DCHECK_GT(kNumGoogleColors, 0u);
+ DCHECK_GE(min_contrast, 0.0f);
+ DCHECK_LE(min_contrast, max_contrast_with_nearer);
+
+ // First set up `lum_colors`, the corresponding relative luminances of
+ // `colors`. These could be precomputed and recorded next to `kGrey` etc. for
+ // some runtime speedup at the cost of maintenance pain.
+ float lum_colors[kNumGoogleColors];
+ base::ranges::transform(colors, std::begin(lum_colors),
+ &GetRelativeLuminance);
+
+ // This function returns an iterator to the least-contrasting luminance (in
+ // `lum_colors`) to `lum`.
+ const auto find_nearest_lum_it = [&lum_colors](float lum) {
+ // Find the first luminance (since they're sorted decreasing) <= `lum`.
+ const float* it =
+ base::ranges::lower_bound(lum_colors, lum, base::ranges::greater());
+ // If applicable, check against the next greater luminance for whichever is
+ // lower-contrast.
+ if (it == std::cend(lum_colors) ||
+ ((it != std::cbegin(lum_colors)) &&
+ (GetContrastRatio(lum, *it) > GetContrastRatio(*(it - 1), lum)))) {
+ --it;
+ }
+ return it;
+ };
+
+ // Compute `src_it`, the element in `lum_colors` which is closest to `color`.
+ const float* src_it = find_nearest_lum_it(GetRelativeLuminance(color));
+
+ // Compute the background luminances.
+ const bool one_bg = background_color_a == background_color_b;
+ const float lum_a = GetRelativeLuminance(background_color_a);
+ const float lum_b = one_bg ? lum_a : GetRelativeLuminance(background_color_b);
+
+ // Compute `lum_mid`, the luminance between `lum_a` and `lum_b` that contrasts
+ // equally with both.
+ const float lum_mid =
+ one_bg ? lum_a : (std::sqrt((lum_a + 0.05f) * (lum_b + 0.05f)) - 0.05f);
+
+ // This function returns the luminance of whichever background contrasts less
+ // with some given luminance (the "nearer background").
+ const auto bg_lum_near_lum = [&](float lum) {
+ return ((lum_a > lum_b) == (lum > lum_mid)) ? lum_a : lum_b;
+ };
+
+ // Compute the contrast of `src_it` against the nearer background.
+ const float nearer_bg_lum = bg_lum_near_lum(*src_it);
+ const float src_contrast_with_near = GetContrastRatio(*src_it, nearer_bg_lum);
+
+ // This function returns the first element E, moving from `begin` towards
+ // `end` (inclusive), which does not satisfy `comp(proj(E), threshold)`. In
+ // other words, this is basically a direction-agnostic lower_bound().
+ const auto first_across_threshold = [&](const float* begin, const float* end,
+ float threshold, auto comp,
+ auto proj) {
+ if (end >= begin) {
+ return base::ranges::lower_bound(begin, end, threshold, comp, proj);
+ }
+ const auto res_it_reversed = base::ranges::lower_bound(
+ std::make_reverse_iterator(begin + 1),
+ std::make_reverse_iterator(end + 1), threshold, comp, proj);
+ return res_it_reversed.base() - 1;
+ };
+
+ // Compute `res_it`, the desired result element in `lum_colors`. Start with
+ // `src_it`, then adjust depending on the contrast against the nearer
+ // background.
+ const float* res_it = src_it;
+ if (src_contrast_with_near < min_contrast) {
+ // Need to increase contrast. This will be done by iterating through
+ // `lum_colors` towards a target element with sufficient contrast. The three
+ // potential targets are the two endpoints and (if there are two
+ // backgrounds) the element nearest `lum_mid`.
+ std::vector<const float*> targets = {std::cbegin(lum_colors),
+ std::cend(lum_colors) - 1};
+ const bool src_darker_than_bg_a = *src_it < lum_a;
+ if (one_bg) {
+ // To avoid inverting the relationship between source and background,
+ // prefer the endpoint on the "same side" of the background as the source,
+ // then the other endpoint.
+ if (src_darker_than_bg_a) {
+ std::swap(targets[0], targets[1]);
+ }
+ } else if (src_darker_than_bg_a == (*src_it < lum_b)) {
+ // The source is either lighter or darker than both backgrounds, so prefer
+ // the endpoint on the "same side", then the midpoint, then the other
+ // endpoint.
+ if (src_darker_than_bg_a) {
+ std::swap(targets[0], targets[1]);
+ }
+ targets.insert(targets.cbegin() + 1, find_nearest_lum_it(lum_mid));
+ } else {
+ // The source is between the two backgrounds, so prefer the midpoint, then
+ // the endpoint on the "same side" of the midpoint as the source, then the
+ // other endpoint.
+ if (*src_it < lum_mid) {
+ std::swap(targets[0], targets[1]);
+ }
+ targets.insert(targets.cbegin(), find_nearest_lum_it(lum_mid));
+ }
+
+ // Set `targ_it` to the first target in the priority list that has at least
+ // `min_contrast` against the nearer background. If none of the targets meet
+ // the contrast threshold, use the one with the best contrast.
+ const float* targ_it;
+ float best_contrast = 0;
+ const auto proj = [&](float lum) {
+ return GetContrastRatio(lum, bg_lum_near_lum(lum));
+ };
+ for (const float* elem : targets) {
+ const float contrast = proj(*elem);
+ if (contrast > best_contrast) {
+ targ_it = elem;
+ best_contrast = contrast;
+ if (best_contrast >= min_contrast) {
+ break;
+ }
}
}
- return colors[0];
+
+ if (best_contrast < min_contrast) {
+ // Couldn't meet the threshold, so `targ_it` is the best possible result.
+ res_it = targ_it;
+ } else {
+ // `targ_it` has sufficient contrast. Since `src_it` is already known to
+ // have insufficient contrast, move it one step towards `targ_it`.
+ src_it = (targ_it < src_it) ? (src_it - 1) : (src_it + 1);
+
+ // Now keep moving towards `targ_it` until contrast is sufficient.
+ res_it = first_across_threshold(src_it, targ_it, min_contrast,
+ base::ranges::less(), proj);
+ }
+ } else if (src_contrast_with_near > max_contrast_with_nearer) {
+ // Need to reduce contrast if possible by moving toward the nearer
+ // background. Compute `targ_it`, the element in `lum_colors` whose
+ // luminance is closest to the nearer background while staying on the "same
+ // side" as `src_it`. (This intentionally allows `targ_it` to match the
+ // nearer background's luminance exactly, in case `min_contrast == 0`.)
+ const auto* targ_it =
+ (*src_it > nearer_bg_lum)
+ ? (std::upper_bound(src_it, std::cend(lum_colors), nearer_bg_lum,
+ std::greater<>()) -
+ 1)
+ : std::lower_bound(std::cbegin(lum_colors), src_it, nearer_bg_lum,
+ std::greater<>());
+
+ // Ensure `targ_it` reaches `min_contrast` against the nearer background by
+ // moving toward `src_it`.
+ const auto proj = [&](float lum) {
+ return GetContrastRatio(lum, nearer_bg_lum);
+ };
+ targ_it = first_across_threshold(targ_it, src_it, min_contrast,
+ base::ranges::less(), proj);
+
+ // Now move `res_it` towards `targ_it` until contrast is sufficiently low.
+ res_it = first_across_threshold(src_it, targ_it, max_contrast_with_nearer,
+ base::ranges::greater(), proj);
}
- // For light backgrounds we start at 400 and go up (toward darker colors).
- constexpr size_t kLightBackgroundStartIndex = 4;
- static_assert(kBlue[kLightBackgroundStartIndex] == gfx::kGoogleBlue400,
- "The start index needs to match kGoogleBlue400");
- for (size_t i = kLightBackgroundStartIndex; i < kNumGoogleColors - 1; ++i) {
- if (GetContrastRatio(GetRelativeLuminance(colors[i]),
- background_luminance) > min_contrast) {
- return colors[i];
- }
+ // Convert `res_it` back to a color.
+ return colors[res_it - std::begin(lum_colors)];
+}
+
+template <typename T>
+SkColor PickGoogleColorImpl(SkColor color, T pick_color) {
+ HSL hsl;
+ SkColorToHSL(color, &hsl);
+ if (hsl.s < 0.1) {
+ // Low saturation, let this be a grey.
+ return pick_color(kGrey);
}
- return colors[kNumGoogleColors - 1];
+
+ // Map hue to angles for readability.
+ const float color_angle = hsl.h * 360;
+
+ // Hues in comments below are of the corresponding kGoogleXXX500 color.
+ // Every cutoff is a halfway point between the two neighboring hue values to
+ // provide as fair of a representation as possible for what color should be
+ // used.
+ // RED: 4
+ if (color_angle < 15)
+ return pick_color(kRed);
+ // ORANGE: 26
+ if (color_angle < 35)
+ return pick_color(kOrange);
+ // YELLOW: 44
+ if (color_angle < 90)
+ return pick_color(kYellow);
+ // GREEN: 136
+ if (color_angle < 163)
+ return pick_color(kGreen);
+ // CYAN: 189
+ // In dark mode, the Mac system blue hue is right on the border between a
+ // kGoogleCyan and kGoogleBlue color, so the cutoff point is tweaked to make
+ // it map to a kGoogleBlue color.
+ if (color_angle < 202)
+ return pick_color(kCyan);
+ // BLUE: 217
+ if (color_angle < 245)
+ return pick_color(kBlue);
+ // PURPLE: 272
+ if (color_angle < 284)
+ return pick_color(kPurple);
+ // MAGENTA: 295
+ if (color_angle < 311)
+ return pick_color(kMagenta);
+ // PINK: 326
+ if (color_angle < 345)
+ return pick_color(kPink);
+
+ // End of hue wheel is red.
+ return pick_color(kRed);
}
} // namespace
SkColor PickGoogleColor(SkColor color,
SkColor background_color,
- float min_contrast) {
- HSL hsl;
- SkColorToHSL(color, &hsl);
- if (hsl.s < 0.1) {
- // Low saturation, let this be a grey.
- return PickGoogleColor(kGrey, background_color, min_contrast);
- }
+ float min_contrast,
+ float max_contrast) {
+ const auto pick_color = [&](const SkColor(&colors)[kNumGoogleColors]) {
+ return PickGoogleColor(colors, color, background_color, background_color,
+ min_contrast, max_contrast);
+ };
+ return PickGoogleColorImpl(color, pick_color);
+}
- // Map hue to angles for readability.
- const float color_angle = hsl.h * 360;
-
- // Hues in comments below are accent colors from MacOS 11.3.1 light mode as
- // point of reference.
- // TODO(pbos): Complement this with more Google colors and verify the hue
- // ranges, this currently knows about enough colors to pick a corresponding
- // color correctly from MacOS accent colors.
- // RED: 357.654
- if (color_angle < 20)
- return PickGoogleColor(kRed, background_color, min_contrast);
- // ORANGE: 28.0687
- if (color_angle < 40)
- return PickGoogleColor(kOrange, background_color, min_contrast);
- // YELLOW: 44.4156
- if (color_angle < 70)
- return PickGoogleColor(kYellow, background_color, min_contrast);
- // GREEN: 105.484
- if (color_angle < 160)
- return PickGoogleColor(kGreen, background_color, min_contrast);
- // BLUE: 214.672
- if (color_angle < 250)
- return PickGoogleColor(kBlue, background_color, min_contrast);
- // PURPLE: 299.362
- if (color_angle < 310)
- return PickGoogleColor(kPurple, background_color, min_contrast);
- // PINK: 331.685
- if (color_angle < 345)
- return PickGoogleColor(kPink, background_color, min_contrast);
-
- // End of hue wheel is red.
- return PickGoogleColor(kRed, background_color, min_contrast);
+SkColor PickGoogleColorTwoBackgrounds(SkColor color,
+ SkColor background_color_a,
+ SkColor background_color_b,
+ float min_contrast,
+ float max_contrast_with_nearer) {
+ const auto pick_color = [&](const SkColor(&colors)[kNumGoogleColors]) {
+ return PickGoogleColor(colors, color, background_color_a,
+ background_color_b, min_contrast,
+ max_contrast_with_nearer);
+ };
+ return PickGoogleColorImpl(color, pick_color);
}
float GetContrastRatio(SkColor color_a, SkColor color_b) {
@@ -203,6 +390,11 @@
GetRelativeLuminance(color_b));
}
+float GetContrastRatio(SkColor4f color_a, SkColor4f color_b) {
+ return GetContrastRatio(GetRelativeLuminance4f(color_a),
+ GetRelativeLuminance4f(color_b));
+}
+
float GetContrastRatio(float luminance_a, float luminance_b) {
DCHECK_GE(luminance_a, 0.0f);
DCHECK_GE(luminance_b, 0.0f);
@@ -213,9 +405,12 @@
}
float GetRelativeLuminance(SkColor color) {
- return (0.2126f * Linearize(SkColorGetR(color))) +
- (0.7152f * Linearize(SkColorGetG(color))) +
- (0.0722f * Linearize(SkColorGetB(color)));
+ return GetRelativeLuminance4f(SkColor4f::FromColor(color));
+}
+
+float GetRelativeLuminance4f(SkColor4f color) {
+ return (0.2126f * Linearize(color.fR)) + (0.7152f * Linearize(color.fG)) +
+ (0.0722f * Linearize(color.fB));
}
uint8_t GetLuma(SkColor color) {
@@ -478,7 +673,7 @@
}
SkColor GetSysSkColor(int which) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return skia::COLORREFToSkColor(GetSysColor(which));
#else
NOTIMPLEMENTED();
@@ -500,11 +695,20 @@
base::NumberToString(SkColorGetA(color) / 255.0).c_str());
}
+std::string SkColor4fToRgbaString(SkColor4f color) {
+ return base::StringPrintf("rgba(%f, %f, %f, %f", color.fR, color.fG, color.fB,
+ color.fA);
+}
+
std::string SkColorToRgbString(SkColor color) {
return base::StringPrintf("%d,%d,%d", SkColorGetR(color), SkColorGetG(color),
SkColorGetB(color));
}
+std::string SkColor4fToRgbString(SkColor4f color) {
+ return base::StringPrintf("rgba(%f, %f, %f", color.fR, color.fG, color.fB);
+}
+
SkColor SetDarkestColorForTesting(SkColor color) {
const SkColor previous_darkest_color = g_darkest_color;
g_darkest_color = color;
diff --git a/ui/gfx/color_utils.h b/ui/gfx/color_utils.h
index 5d5c430..5677c2c 100644
--- a/ui/gfx/color_utils.h
+++ b/ui/gfx/color_utils.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -28,6 +28,9 @@
SkColor color;
};
+// The maximum contrast that can be achieved (i.e. white against black).
+constexpr float kMaximumPossibleContrast = 21.0f;
+
// The minimum contrast between text and background that is still readable.
// This value is taken from w3c accessibility guidelines.
constexpr float kMinimumReadableContrastRatio = 4.5f;
@@ -40,12 +43,14 @@
// Determines the contrast ratio of two colors or two relative luminance values
// (as computed by RelativeLuminance()), calculated according to
// http://www.w3.org/TR/WCAG20/#contrast-ratiodef .
+GFX_EXPORT float GetContrastRatio(SkColor4f color_a, SkColor4f color_b);
GFX_EXPORT float GetContrastRatio(SkColor color_a, SkColor color_b);
GFX_EXPORT float GetContrastRatio(float luminance_a, float luminance_b);
// The relative luminance of |color|, that is, the weighted sum of the
// linearized RGB components, normalized to 0..1, per BT.709. See
// http://www.w3.org/TR/WCAG20/#relativeluminancedef .
+GFX_EXPORT float GetRelativeLuminance4f(SkColor4f color);
GFX_EXPORT float GetRelativeLuminance(SkColor color);
// The luma of |color|, that is, the weighted sum of the gamma-compressed R'G'B'
@@ -158,18 +163,52 @@
// surface.
GFX_EXPORT SkColor DeriveDefaultIconColor(SkColor text_color);
-// Gets a Google color that matches the hue of `color` and contrasts well
-// enough against `background_color` to meet `min_contrast`. If `color` isn't
-// very saturated, grey will be used instead.
-GFX_EXPORT SkColor PickGoogleColor(SkColor color,
- SkColor background_color,
- float min_contrast);
+// Gets a Google color with a similar hue to `color` and a similar contrast
+// against `background_color`, subject to being at least `min_contrast` and at
+// most `max_contrast`. If `color` isn't very saturated, grey will be used
+// instead.
+//
+// Each of the following constraints takes precedence over the ones below it.
+// 1. Ensure `min_contrast`, if possible, lest the UI become unreadable. If
+// there are no sufficiently-contrasting colors of the desired hue, falls
+// back to white/grey 900.
+// 2. Avoid returning a lighter color than the background if the input was
+// darker, and vice versa. Inverting the relationship between `color` and
+// `background_color` could look odd.
+// 3. Ensure `max_contrast`, if possible, lest some UI elements stick out too
+// much.
+// 4. Adjust the relative luminance of the returned color as little as
+// possible, to minimize distortion of the intended color.
+// Other than prioritizing (1), this order is subjective.
+GFX_EXPORT SkColor
+PickGoogleColor(SkColor color,
+ SkColor background_color,
+ float min_contrast,
+ float max_contrast = kMaximumPossibleContrast);
+
+// Like the version above, but the constraints are modified:
+// 1. Ensure `min_contrast`, if possible, with both backgrounds
+// simultaneously.
+// 2. If the input is lighter than both backgrounds, make it lighter; if it's
+// darker than both, make it darker; if it's between the two, keep it
+// between.
+// 3. Ensure `max_contrast_with_nearer` against the lower-contrast ("nearer")
+// background.
+// 4. Unchanged.
+GFX_EXPORT SkColor PickGoogleColorTwoBackgrounds(
+ SkColor color,
+ SkColor background_color_a,
+ SkColor background_color_b,
+ float min_contrast,
+ float max_contrast_with_nearer = kMaximumPossibleContrast);
// Creates an rgba string for an SkColor. For example: 'rgba(255,0,255,0.5)'.
GFX_EXPORT std::string SkColorToRgbaString(SkColor color);
+GFX_EXPORT std::string SkColor4fToRgbaString(SkColor4f color);
// Creates an rgb string for an SkColor. For example: '255,0,255'.
GFX_EXPORT std::string SkColorToRgbString(SkColor color);
+GFX_EXPORT std::string SkColor4fToRgbString(SkColor4f color);
// Sets the darkest available color to |color|. Returns the previous darkest
// color.
diff --git a/ui/gfx/color_utils_unittest.cc b/ui/gfx/color_utils_unittest.cc
index d3d35e1..0f2d571 100644
--- a/ui/gfx/color_utils_unittest.cc
+++ b/ui/gfx/color_utils_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
+// Copyright 2006-2008 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -182,8 +182,7 @@
TEST(ColorUtils, MidpointLuminanceMatches) {
const SkColor old_darkest_color = SetDarkestColorForTesting(SK_ColorBLACK);
- float darkest, midpoint, lightest;
- std::tie(darkest, midpoint, lightest) = GetLuminancesForTesting();
+ auto [darkest, midpoint, lightest] = GetLuminancesForTesting();
EXPECT_FLOAT_EQ(GetContrastRatio(darkest, midpoint),
GetContrastRatio(midpoint, lightest));
@@ -310,4 +309,124 @@
EXPECT_EQ(color, result.color);
}
+TEST(ColorUtils, PickGoogleColor) {
+ // If the input color already has sufficient contrast, it should be accepted.
+ EXPECT_EQ(gfx::kGoogleBlue800,
+ PickGoogleColor(gfx::kGoogleBlue800, gfx::kGoogleBlue700, 1.1f));
+ EXPECT_EQ(gfx::kGoogleBlue600,
+ PickGoogleColor(gfx::kGoogleBlue600, gfx::kGoogleBlue700, 1.1f));
+
+ // If it does not, it should stay on the same side of the background if
+ // possible.
+ EXPECT_EQ(gfx::kGoogleBlue900,
+ PickGoogleColor(gfx::kGoogleBlue800, gfx::kGoogleBlue700, 1.25f));
+ EXPECT_EQ(gfx::kGoogleBlue500,
+ PickGoogleColor(gfx::kGoogleBlue600, gfx::kGoogleBlue700, 1.25f));
+
+ // If even Blue 900 does not contrast enough, Grey 900 is a slightly darker
+ // color.
+ EXPECT_EQ(gfx::kGoogleGrey900,
+ PickGoogleColor(gfx::kGoogleBlue800, gfx::kGoogleBlue700, 1.5f));
+
+ // If no dark colors have enough contrast, the result should be a lighter
+ // color instead.
+ EXPECT_EQ(gfx::kGoogleBlue200,
+ PickGoogleColor(gfx::kGoogleBlue800, gfx::kGoogleBlue700, 3.0f));
+
+ // If the requested contrast is too high for any color to be sufficient, the
+ // result should be the most-contrasting endpoint.
+ EXPECT_EQ(SK_ColorWHITE,
+ PickGoogleColor(gfx::kGoogleBlue800, gfx::kGoogleBlue700,
+ kMaximumPossibleContrast));
+
+ // Matching the background exactly is reasonable, if the minimum contrast is
+ // zero.
+ EXPECT_EQ(
+ gfx::kGoogleBlue700,
+ PickGoogleColor(gfx::kGoogleBlue800, gfx::kGoogleBlue700, 0.0f, 1.2f));
+
+ // Blue 600 is the only color that fits in the requested contrast window, but
+ // it's on the other side of the background from the input, so something
+ // closer to the input is used instead.
+ EXPECT_EQ(
+ gfx::kGoogleBlue800,
+ PickGoogleColor(gfx::kGoogleBlue900, gfx::kGoogleBlue700, 1.18f, 1.2f));
+}
+
+TEST(ColorUtils, PickGoogleColorTwoBackgrounds) {
+ // If the input color already has sufficient contrast, it should be accepted.
+ EXPECT_EQ(gfx::kGoogleBlue800, PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue800, gfx::kGoogleBlue700,
+ gfx::kGoogleBlue200, 1.1f));
+ EXPECT_EQ(gfx::kGoogleBlue600, PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue600, gfx::kGoogleBlue700,
+ gfx::kGoogleBlue200, 1.1f));
+ EXPECT_EQ(gfx::kGoogleBlue300, PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue300, gfx::kGoogleBlue700,
+ gfx::kGoogleBlue200, 1.1f));
+ EXPECT_EQ(gfx::kGoogleBlue100, PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue100, gfx::kGoogleBlue700,
+ gfx::kGoogleBlue200, 1.1f));
+
+ // If it does not, it should stay on the same side of the background if
+ // possible.
+ EXPECT_EQ(gfx::kGoogleBlue900, PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue800, gfx::kGoogleBlue700,
+ gfx::kGoogleBlue200, 1.25f));
+ EXPECT_EQ(gfx::kGoogleBlue500, PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue600, gfx::kGoogleBlue700,
+ gfx::kGoogleBlue200, 1.25f));
+ EXPECT_EQ(gfx::kGoogleBlue400, PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue300, gfx::kGoogleBlue700,
+ gfx::kGoogleBlue200, 1.3f));
+ EXPECT_EQ(gfx::kGoogleBlue050, PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue100, gfx::kGoogleBlue700,
+ gfx::kGoogleBlue200, 1.3f));
+
+ // If the blue endpoints do not contrast enough, the grey endpoints are
+ // available.
+ EXPECT_EQ(gfx::kGoogleGrey900, PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue800, gfx::kGoogleBlue700,
+ gfx::kGoogleBlue200, 1.5f));
+ EXPECT_EQ(SK_ColorWHITE, PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue100, gfx::kGoogleBlue700,
+ gfx::kGoogleBlue200, 1.5f));
+
+ // If it's not possible to achieve sufficient contrast on the same side of the
+ // background, then the result color should cross to the other side.
+ EXPECT_EQ(gfx::kGoogleBlue500, PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue100, gfx::kGoogleBlue200,
+ gfx::kGoogleBlue900, 1.7f));
+ EXPECT_EQ(gfx::kGoogleBlue100, PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue800, gfx::kGoogleBlue700,
+ gfx::kGoogleBlue600, 3.0f));
+
+ // If the requested contrast is too high for any color to be sufficient, the
+ // result should be the most-contrasting point.
+ EXPECT_EQ(SK_ColorWHITE, PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue800, gfx::kGoogleBlue700,
+ gfx::kGoogleBlue600, kMaximumPossibleContrast));
+ EXPECT_EQ(gfx::kGoogleGrey900,
+ PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue100, gfx::kGoogleBlue200, gfx::kGoogleBlue300,
+ kMaximumPossibleContrast));
+ EXPECT_EQ(gfx::kGoogleBlue400,
+ PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue100, gfx::kGoogleBlue900, gfx::kGoogleBlue050,
+ kMaximumPossibleContrast));
+
+ // Matching the background exactly is reasonable, if the minimum contrast is
+ // zero.
+ EXPECT_EQ(gfx::kGoogleBlue700, PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue800, gfx::kGoogleBlue700,
+ gfx::kGoogleBlue600, 0.0f, 1.2f));
+
+ // Blue 600 is the only color that fits in the requested contrast window, but
+ // it's on the other side of the background from the input, so something
+ // closer to the input is used instead.
+ EXPECT_EQ(gfx::kGoogleBlue800, PickGoogleColorTwoBackgrounds(
+ gfx::kGoogleBlue900, gfx::kGoogleBlue700,
+ gfx ::kGoogleBlue500, 1.18f, 1.2f));
+}
+
} // namespace color_utils
diff --git a/ui/gfx/decorated_text.cc b/ui/gfx/decorated_text.cc
index f8b2fd1..e036ac1 100644
--- a/ui/gfx/decorated_text.cc
+++ b/ui/gfx/decorated_text.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/decorated_text.h b/ui/gfx/decorated_text.h
index 9d53d05..220d4bc 100644
--- a/ui/gfx/decorated_text.h
+++ b/ui/gfx/decorated_text.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/decorated_text_mac.h b/ui/gfx/decorated_text_mac.h
index ad1aa59..8044b9d 100644
--- a/ui/gfx/decorated_text_mac.h
+++ b/ui/gfx/decorated_text_mac.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/decorated_text_mac.mm b/ui/gfx/decorated_text_mac.mm
index 80942a6..eb59d1e 100644
--- a/ui/gfx/decorated_text_mac.mm
+++ b/ui/gfx/decorated_text_mac.mm
@@ -1,11 +1,13 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ui/gfx/decorated_text_mac.h"
#import <Cocoa/Cocoa.h>
+#include <CoreText/CoreText.h>
+#include "base/mac/foundation_util.h"
#import "base/mac/scoped_nsobject.h"
#include "base/strings/sys_string_conversions.h"
#include "ui/gfx/decorated_text.h"
@@ -29,8 +31,10 @@
NSMutableDictionary* attrs = [NSMutableDictionary dictionary];
NSRange range = attribute.range.ToNSRange();
- if (attribute.font.GetNativeFont())
- attrs[NSFontAttributeName] = attribute.font.GetNativeFont();
+ CTFontRef font = attribute.font.GetCTFont();
+ if (font) {
+ attrs[NSFontAttributeName] = base::mac::CFToNSCast(font);
+ }
// NSFont does not have underline as an attribute. Hence handle it
// separately.
diff --git a/ui/gfx/delegated_ink_metadata.cc b/ui/gfx/delegated_ink_metadata.cc
index eea84b1..befc6aa 100644
--- a/ui/gfx/delegated_ink_metadata.cc
+++ b/ui/gfx/delegated_ink_metadata.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/delegated_ink_metadata.h b/ui/gfx/delegated_ink_metadata.h
index 04b8c7c..e5f77bf 100644
--- a/ui/gfx/delegated_ink_metadata.h
+++ b/ui/gfx/delegated_ink_metadata.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -14,13 +14,20 @@
namespace gfx {
+// Maximum number of points that can be drawn. This is used to limit the total
+// number of ink trail tokens that we will store, and the total number of points
+// that we will store to provide to the Direct Composition APIs. It should match
+// the exact number of points that the OS Compositor will store to draw as part
+// of a trail.
+inline constexpr int kMaximumNumberOfDelegatedInkPoints = 128;
+
// This class stores all the metadata that is gathered when the WebAPI
// updateInkTrailStartPoint is called. This metadata flows from blink,
// through cc, and into viz in order to produce a delegated ink trail on the
// end of what was already rendered.
//
// Explainer for the feature:
-// https://github.com/WICG/ink-enhancement/blob/master/README.md
+// https://github.com/WICG/ink-enhancement/blob/main/README.md
class GFX_EXPORT DelegatedInkMetadata {
public:
DelegatedInkMetadata() = default;
@@ -62,7 +69,13 @@
bool is_hovering() const { return is_hovering_; }
void set_frame_time(base::TimeTicks frame_time) { frame_time_ = frame_time; }
-
+ uint64_t trace_id() const {
+ // Use mask to distinguish from DelegatedInkPoint::trace_id().
+ // Using microseconds provides uniqueness of trace_id per
+ // DelegatedInkMetadata.
+ return static_cast<uint64_t>(timestamp_.since_origin().InMicroseconds()) |
+ (uint64_t{1} << 63);
+ }
std::string ToString() const;
private:
diff --git a/ui/gfx/delegated_ink_point.cc b/ui/gfx/delegated_ink_point.cc
index 6240c27..7c5813f 100644
--- a/ui/gfx/delegated_ink_point.cc
+++ b/ui/gfx/delegated_ink_point.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/delegated_ink_point.h b/ui/gfx/delegated_ink_point.h
index 92d1178..3b41a49 100644
--- a/ui/gfx/delegated_ink_point.h
+++ b/ui/gfx/delegated_ink_point.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -29,7 +29,7 @@
// the screen, connected to the end of the already rendered ink stroke.
//
// Explainer for the feature:
-// https://github.com/WICG/ink-enhancement/blob/master/README.md
+// https://github.com/WICG/ink-enhancement/blob/main/README.md
class GFX_EXPORT DelegatedInkPoint {
public:
DelegatedInkPoint() = default;
@@ -44,6 +44,12 @@
std::string ToString() const;
bool MatchesDelegatedInkMetadata(const DelegatedInkMetadata* metadata) const;
+ uint64_t trace_id() const {
+ // Use mask to distinguish from DelegatedInkMetadata::trace_id().
+ // Using microseconds provides uniqueness of trace_id per
+ // DelegatedInkPoint.
+ return timestamp_.since_origin().InMicroseconds() & 0x7fffffffffffffff;
+ }
private:
friend struct mojo::StructTraits<mojom::DelegatedInkPointDataView,
diff --git a/ui/gfx/delegated_ink_unittest.cc b/ui/gfx/delegated_ink_unittest.cc
index 455d4bf..b2aa67e 100644
--- a/ui/gfx/delegated_ink_unittest.cc
+++ b/ui/gfx/delegated_ink_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/display_color_spaces.cc b/ui/gfx/display_color_spaces.cc
index a5b8e14..10df605 100644
--- a/ui/gfx/display_color_spaces.cc
+++ b/ui/gfx/display_color_spaces.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -41,10 +41,11 @@
} // namespace
DisplayColorSpaces::DisplayColorSpaces() {
- for (auto& color_space : color_spaces_)
- color_space = gfx::ColorSpace::CreateSRGB();
- for (auto& buffer_format : buffer_formats_)
- buffer_format = DefaultBufferFormat();
+ // TODO(crbug/1309228): Revert back to range-based for loops if possible
+ for (size_t i = 0; i < kConfigCount; i++) {
+ color_spaces_[i] = gfx::ColorSpace::CreateSRGB();
+ buffer_formats_[i] = DefaultBufferFormat();
+ }
}
DisplayColorSpaces::DisplayColorSpaces(const gfx::DisplayColorSpaces&) =
@@ -57,15 +58,16 @@
: DisplayColorSpaces() {
if (!c.IsValid())
return;
- for (auto& color_space : color_spaces_)
- color_space = c;
+ primaries_ = c.GetPrimaries();
+ for (size_t i = 0; i < kConfigCount; i++) // NOLINT (modernize-loop-convert)
+ color_spaces_[i] = c;
}
-DisplayColorSpaces::DisplayColorSpaces(const ColorSpace& c, BufferFormat f) {
- for (auto& color_space : color_spaces_)
- color_space = c.IsValid() ? c : gfx::ColorSpace::CreateSRGB();
- for (auto& buffer_format : buffer_formats_)
- buffer_format = f;
+DisplayColorSpaces::DisplayColorSpaces(const ColorSpace& c, BufferFormat f)
+ : DisplayColorSpaces(c) {
+ for (size_t i = 0; i < kConfigCount; i++) {
+ buffer_formats_[i] = f;
+ }
}
void DisplayColorSpaces::SetOutputBufferFormats(
@@ -189,7 +191,11 @@
if (buffer_formats_[i] != other.buffer_formats_[i])
return false;
}
- if (sdr_white_level_ != other.sdr_white_level_)
+ if (primaries_ != other.primaries_)
+ return false;
+ if (sdr_max_luminance_nits_ != other.sdr_max_luminance_nits_)
+ return false;
+ if (hdr_max_luminance_relative_ != other.hdr_max_luminance_relative_)
return false;
return true;
diff --git a/ui/gfx/display_color_spaces.h b/ui/gfx/display_color_spaces.h
index 85d3d8e..8763a08 100644
--- a/ui/gfx/display_color_spaces.h
+++ b/ui/gfx/display_color_spaces.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,7 +8,9 @@
#include <string>
#include <vector>
+#include "skia/ext/skcolorspace_primaries.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/skia/include/core/SkColorSpace.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/color_space_export.h"
@@ -77,19 +79,21 @@
BufferFormat GetOutputBufferFormat(ContentColorUsage color_usage,
bool needs_alpha) const;
- // Set the custom SDR white level, in nits. This is a non-default value only
+ // Set the maximum SDR luminance, in nits. This is a non-default value only
// on Windows.
- void SetSDRWhiteLevel(float sdr_white_level) {
- sdr_white_level_ = sdr_white_level;
+ void SetSDRMaxLuminanceNits(float sdr_max_luminance_nits) {
+ sdr_max_luminance_nits_ = sdr_max_luminance_nits;
}
- float GetSDRWhiteLevel() const { return sdr_white_level_; }
+ float GetSDRMaxLuminanceNits() const { return sdr_max_luminance_nits_; }
- void set_hdr_static_metadata(
- absl::optional<HDRStaticMetadata> hdr_static_metadata) {
- hdr_static_metadata_ = hdr_static_metadata;
+ // Set the maximum luminance that HDR content can display. This is represented
+ // as a multiple of the SDR white luminance (so a display that is incapable of
+ // HDR would have a value of 1.0).
+ void SetHDRMaxLuminanceRelative(float hdr_max_luminance_relative) {
+ hdr_max_luminance_relative_ = hdr_max_luminance_relative;
}
- const absl::optional<HDRStaticMetadata>& hdr_static_metadata() const {
- return hdr_static_metadata_;
+ float GetHDRMaxLuminanceRelative() const {
+ return hdr_max_luminance_relative_;
}
// TODO(https://crbug.com/1116870): These helper functions exist temporarily
@@ -110,6 +114,12 @@
// Return true if the HDR color spaces are, indeed, HDR.
bool SupportsHDR() const;
+ // Return the primaries that define the color gamut of the display.
+ const SkColorSpacePrimaries& GetPrimaries() const { return primaries_; }
+ void SetPrimaries(const SkColorSpacePrimaries& primaries) {
+ primaries_ = primaries;
+ }
+
// Output as a vector of strings. This is a helper function for printing in
// about:gpu. All output vectors will be the same length. Each entry will be
// the configuration name, its buffer format, and its color space.
@@ -128,9 +138,9 @@
gfx::ColorSpace color_spaces_[kConfigCount];
gfx::BufferFormat buffer_formats_[kConfigCount];
- float sdr_white_level_ = ColorSpace::kDefaultSDRWhiteLevel;
- // By definition this only applies to ContentColorUsage::kHDR.
- absl::optional<HDRStaticMetadata> hdr_static_metadata_;
+ SkColorSpacePrimaries primaries_ = SkNamedPrimariesExt::kSRGB;
+ float sdr_max_luminance_nits_ = ColorSpace::kDefaultSDRWhiteLevel;
+ float hdr_max_luminance_relative_ = 1.f;
};
} // namespace gfx
diff --git a/ui/gfx/extension_set.cc b/ui/gfx/extension_set.cc
index d61e600..df4a32f 100644
--- a/ui/gfx/extension_set.cc
+++ b/ui/gfx/extension_set.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/extension_set.h b/ui/gfx/extension_set.h
index 3a699f4..9fe20e5 100644
--- a/ui/gfx/extension_set.h
+++ b/ui/gfx/extension_set.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/favicon_size.cc b/ui/gfx/favicon_size.cc
index d0ba48a..66fbcad 100644
--- a/ui/gfx/favicon_size.cc
+++ b/ui/gfx/favicon_size.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/favicon_size.h b/ui/gfx/favicon_size.h
index ad51a9b..8c18b24 100644
--- a/ui/gfx/favicon_size.h
+++ b/ui/gfx/favicon_size.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/font.cc b/ui/gfx/font.cc
index 50a071a..6ad86c8 100644
--- a/ui/gfx/font.cc
+++ b/ui/gfx/font.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,6 +10,10 @@
#include "build/build_config.h"
#include "ui/gfx/platform_font.h"
+#ifndef NDEBUG
+#include <ostream>
+#endif
+
namespace gfx {
////////////////////////////////////////////////////////////////////////////////
@@ -26,10 +30,9 @@
return *this;
}
-#if defined(OS_APPLE)
-Font::Font(NativeFont native_font)
- : platform_font_(PlatformFont::CreateFromNativeFont(native_font)) {
-}
+#if BUILDFLAG(IS_APPLE)
+Font::Font(CTFontRef ct_font)
+ : platform_font_(PlatformFont::CreateFromCTFont(ct_font)) {}
#endif
Font::Font(PlatformFont* platform_font) : platform_font_(platform_font) {
@@ -90,9 +93,9 @@
return platform_font_->GetFontRenderParams();
}
-#if defined(OS_APPLE)
-NativeFont Font::GetNativeFont() const {
- return platform_font_->GetNativeFont();
+#if BUILDFLAG(IS_APPLE)
+CTFontRef Font::GetCTFont() const {
+ return platform_font_->GetCTFont();
}
#endif
diff --git a/ui/gfx/font.h b/ui/gfx/font.h
index f797b0d..35c7ebb 100644
--- a/ui/gfx/font.h
+++ b/ui/gfx/font.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,11 +7,15 @@
#include <string>
-#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
#include "build/build_config.h"
#include "ui/gfx/gfx_export.h"
#include "ui/gfx/native_widget_types.h"
+#if BUILDFLAG(IS_APPLE)
+#include <CoreText/CoreText.h>
+#endif
+
namespace gfx {
struct FontRenderParams;
@@ -59,9 +63,9 @@
Font(const Font& other);
Font& operator=(const Font& other);
-#if defined(OS_APPLE)
- // Creates a font from the specified native font.
- explicit Font(NativeFont native_font);
+#if BUILDFLAG(IS_APPLE)
+ // Creates a font from the specified CTFontRef.
+ explicit Font(CTFontRef ct_font);
#endif
// Constructs a Font object with the specified PlatformFont object. The Font
@@ -116,11 +120,10 @@
// Returns an object describing how the font should be rendered.
const FontRenderParams& GetFontRenderParams() const;
-#if defined(OS_APPLE)
- // Returns the native font handle.
- // Lifetime lore:
- // Mac: The object is owned by the system and should not be released.
- NativeFont GetNativeFont() const;
+#if BUILDFLAG(IS_APPLE)
+ // Returns the CTFontRef. This is owned by the gfx::Font as per the standard
+ // "get" idiom.
+ CTFontRef GetCTFont() const;
#endif
// Raw access to the underlying platform font implementation.
diff --git a/ui/gfx/font_fallback.h b/ui/gfx/font_fallback.h
index 001ec40..795544a 100644
--- a/ui/gfx/font_fallback.h
+++ b/ui/gfx/font_fallback.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,6 +8,7 @@
#include <string>
#include <vector>
+#include "base/strings/string_piece_forward.h"
#include "build/build_config.h"
#include "ui/gfx/font.h"
#include "ui/gfx/gfx_export.h"
diff --git a/ui/gfx/font_fallback_linux.cc b/ui/gfx/font_fallback_linux.cc
index 5f3240c..1286bcb 100644
--- a/ui/gfx/font_fallback_linux.cc
+++ b/ui/gfx/font_fallback_linux.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,11 +10,13 @@
#include <memory>
#include <string>
-#include "base/containers/mru_cache.h"
+#include "base/containers/lru_cache.h"
#include "base/files/file_path.h"
#include "base/lazy_instance.h"
#include "base/memory/ptr_util.h"
+#include "base/memory/raw_ptr.h"
#include "base/no_destructor.h"
+#include "base/strings/string_piece.h"
#include "base/trace_event/trace_event.h"
#include "third_party/icu/source/common/unicode/uchar.h"
#include "third_party/icu/source/common/unicode/utf16.h"
@@ -175,12 +177,12 @@
FontRenderParams font_params_;
// Font code points coverage.
- FcCharSet* charset_;
+ raw_ptr<FcCharSet> charset_;
};
using FallbackFontEntries = std::vector<FallbackFontEntry>;
using FallbackFontEntriesCache =
- base::MRUCache<FallbackFontKey, FallbackFontEntries>;
+ base::LRUCache<FallbackFontKey, FallbackFontEntries>;
// The fallback font cache is a mapping from a font to the potential fallback
// fonts with their codepoint coverage.
@@ -194,7 +196,7 @@
// The fallback fonts cache is a mapping from a font family name to its
// potential fallback fonts.
using FallbackFontList = std::vector<Font>;
-using FallbackFontListCache = base::MRUCache<std::string, FallbackFontList>;
+using FallbackFontListCache = base::LRUCache<std::string, FallbackFontList>;
FallbackFontListCache* GetFallbackFontListCacheInstance() {
constexpr int kFallbackCacheSize = 64;
@@ -414,7 +416,7 @@
FallbackFontData fallback_font_;
// supported_characters_ is owned by the parent
// FcFontSet and should never be freed.
- FcCharSet* supported_characters_;
+ raw_ptr<FcCharSet> supported_characters_;
};
class CachedFontSet {
@@ -501,7 +503,7 @@
}
}
- FcFontSet* font_set_; // Owned by this object.
+ raw_ptr<FcFontSet> font_set_; // Owned by this object.
// CachedFont has a FcCharset* which points into the FcFontSet.
// If the FcFontSet is ever destroyed, the fallback list
// must be cleared first.
diff --git a/ui/gfx/font_fallback_linux.h b/ui/gfx/font_fallback_linux.h
index 7a768690..f58814d 100644
--- a/ui/gfx/font_fallback_linux.h
+++ b/ui/gfx/font_fallback_linux.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/font_fallback_linux_unittest.cc b/ui/gfx/font_fallback_linux_unittest.cc
index ec156cf..679c2ba 100644
--- a/ui/gfx/font_fallback_linux_unittest.cc
+++ b/ui/gfx/font_fallback_linux_unittest.cc
@@ -1,10 +1,11 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/font_fallback_linux.h"
#include "base/files/file_path.h"
+#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/font.h"
diff --git a/ui/gfx/font_fallback_mac.mm b/ui/gfx/font_fallback_mac.mm
index aee2249..472d8fb 100644
--- a/ui/gfx/font_fallback_mac.mm
+++ b/ui/gfx/font_fallback_mac.mm
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,6 +11,7 @@
#include "base/mac/foundation_util.h"
#import "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
+#include "base/strings/string_piece.h"
#import "base/strings/sys_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "third_party/icu/source/common/unicode/uchar.h"
@@ -34,7 +35,7 @@
} // namespace
std::vector<Font> GetFallbackFonts(const Font& font) {
- DCHECK(font.GetNativeFont());
+ DCHECK(font.GetCTFont());
// On Mac "There is a system default cascade list (which is polymorphic, based
// on the user's language setting and current font)" - CoreText Programming
// Guide.
@@ -42,8 +43,7 @@
stringArrayForKey:@"AppleLanguages"];
CFArrayRef languages_cf = base::mac::NSToCFCast(languages);
base::ScopedCFTypeRef<CFArrayRef> cascade_list(
- CTFontCopyDefaultCascadeListForLanguages(
- static_cast<CTFontRef>(font.GetNativeFont()), languages_cf));
+ CTFontCopyDefaultCascadeListForLanguages(font.GetCTFont(), languages_cf));
std::vector<Font> fallback_fonts;
if (!cascade_list)
@@ -56,8 +56,9 @@
CFArrayGetValueAtIndex(cascade_list, i));
base::ScopedCFTypeRef<CTFontRef> fallback_font(
CTFontCreateWithFontDescriptor(descriptor, 0.0, nullptr));
- if (fallback_font.get())
- fallback_fonts.push_back(Font(static_cast<NSFont*>(fallback_font.get())));
+ if (fallback_font.get()) {
+ fallback_fonts.emplace_back(fallback_font.get());
+ }
}
if (fallback_fonts.empty())
diff --git a/ui/gfx/font_fallback_mac_unittest.cc b/ui/gfx/font_fallback_mac_unittest.cc
index dbb1724..c633bf0 100644
--- a/ui/gfx/font_fallback_mac_unittest.cc
+++ b/ui/gfx/font_fallback_mac_unittest.cc
@@ -1,9 +1,10 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/font_fallback.h"
+#include "base/strings/string_piece.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/ui/gfx/font_fallback_skia.cc b/ui/gfx/font_fallback_skia.cc
index 29a5cc0..5ab912c 100644
--- a/ui/gfx/font_fallback_skia.cc
+++ b/ui/gfx/font_fallback_skia.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,6 +7,7 @@
#include <string>
#include <vector>
+#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
diff --git a/ui/gfx/font_fallback_skia_impl.cc b/ui/gfx/font_fallback_skia_impl.cc
index a2eb422..e79d291 100644
--- a/ui/gfx/font_fallback_skia_impl.cc
+++ b/ui/gfx/font_fallback_skia_impl.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/font_fallback_skia_impl.h b/ui/gfx/font_fallback_skia_impl.h
index 1908dee..be5b1a5 100644
--- a/ui/gfx/font_fallback_skia_impl.h
+++ b/ui/gfx/font_fallback_skia_impl.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/font_fallback_skia_unittest.cc b/ui/gfx/font_fallback_skia_unittest.cc
index 01bd3f2..c2e70de 100644
--- a/ui/gfx/font_fallback_skia_unittest.cc
+++ b/ui/gfx/font_fallback_skia_unittest.cc
@@ -1,10 +1,11 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/font_fallback.h"
#include "base/logging.h"
+#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -45,7 +46,7 @@
}
}
-#if !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
+#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA)
// TODO(sergeyu): Fuchsia doesn't not support locale for font fallbacks.
// TODO(etienneb): Android doesn't allow locale override, unless the language
// is added in the system UI.
@@ -91,6 +92,6 @@
EXPECT_NE(fallback_font_zh_cn.GetFontName(), fallback_font_ko.GetFontName());
EXPECT_NE(fallback_font_ja.GetFontName(), fallback_font_ko.GetFontName());
}
-#endif // !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
+#endif // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_FUCHSIA)
} // namespace gfx
diff --git a/ui/gfx/font_fallback_unittest.cc b/ui/gfx/font_fallback_unittest.cc
index 236ba7c..d662ab1 100644
--- a/ui/gfx/font_fallback_unittest.cc
+++ b/ui/gfx/font_fallback_unittest.cc
@@ -1,12 +1,11 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/font_fallback_win.h"
-
#include <tuple>
-#include "base/cxx17_backports.h"
+#include "base/containers/contains.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/test/task_environment.h"
@@ -16,13 +15,10 @@
#include "third_party/icu/source/common/unicode/uscript.h"
#include "third_party/icu/source/common/unicode/utf16.h"
#include "third_party/skia/include/core/SkTypeface.h"
+#include "ui/gfx/font_fallback_win.h"
#include "ui/gfx/platform_font.h"
#include "ui/gfx/test/font_fallback_test_data.h"
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
namespace gfx {
namespace {
@@ -170,15 +166,6 @@
base_font_option_.weight);
}
-#if defined(OS_WIN)
- // Skip testing this call to GetFallbackFont on older windows versions. Some
- // fonts only got introduced on windows 10 and the test will fail on previous
- // versions.
- const bool is_win10 = base::win::GetVersion() >= base::win::Version::WIN10;
- if (test_case_.is_win10 && !is_win10)
- return;
-#endif
-
// Retrieve the name of the current script.
script_name_ = uscript_getName(test_case_.script);
@@ -205,11 +192,8 @@
// Ensure the fallback font is a part of the validation fallback fonts list.
if (!test_option_.skip_fallback_fonts_validation) {
- bool valid = std::find(test_case_.fallback_fonts.begin(),
- test_case_.fallback_fonts.end(),
- fallback_font.GetFontName()) !=
- test_case_.fallback_fonts.end();
- if (!valid) {
+ if (!base::Contains(test_case_.fallback_fonts,
+ fallback_font.GetFontName())) {
ADD_FAILURE() << "GetFallbackFont failed for '" << script_name_
<< "' invalid fallback font: "
<< fallback_font.GetFontName()
@@ -239,7 +223,7 @@
char16_t text[8];
UErrorCode errorCode = U_ZERO_ERROR;
int text_length =
- uscript_getSampleString(script, text, base::size(text), &errorCode);
+ uscript_getSampleString(script, text, std::size(text), &errorCode);
if (text_length <= 0 || errorCode != U_ZERO_ERROR)
continue;
diff --git a/ui/gfx/font_fallback_win.cc b/ui/gfx/font_fallback_win.cc
index 753b511..4892527 100644
--- a/ui/gfx/font_fallback_win.cc
+++ b/ui/gfx/font_fallback_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,8 +7,8 @@
#include <algorithm>
#include <map>
-#include "base/macros.h"
#include "base/memory/singleton.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
diff --git a/ui/gfx/font_fallback_win.h b/ui/gfx/font_fallback_win.h
index bf6c745..07e7b6c 100644
--- a/ui/gfx/font_fallback_win.h
+++ b/ui/gfx/font_fallback_win.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,7 +10,6 @@
#include <string>
#include <vector>
-#include "base/macros.h"
#include "ui/gfx/font.h"
#include "ui/gfx/font_fallback.h"
diff --git a/ui/gfx/font_fallback_win_unittest.cc b/ui/gfx/font_fallback_win_unittest.cc
index b3b68b3..880bc89 100644
--- a/ui/gfx/font_fallback_win_unittest.cc
+++ b/ui/gfx/font_fallback_win_unittest.cc
@@ -1,13 +1,11 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/font_fallback_win.h"
-#include "base/cxx17_backports.h"
-#include "base/macros.h"
+#include "base/strings/string_piece.h"
#include "base/test/task_environment.h"
-#include "base/win/windows_version.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace gfx {
@@ -91,26 +89,22 @@
// Multiple ending NUL characters.
const char16_t kTest1[] = {0x0540, 0x0541, 0, 0, 0};
EXPECT_FALSE(GetFallbackFont(base_font, kDefaultApplicationLocale,
- base::StringPiece16(kTest1, base::size(kTest1)),
+ base::StringPiece16(kTest1, std::size(kTest1)),
&fallback_font));
// No ending NUL character.
const char16_t kTest2[] = {0x0540, 0x0541};
EXPECT_TRUE(GetFallbackFont(base_font, kDefaultApplicationLocale,
- base::StringPiece16(kTest2, base::size(kTest2)),
+ base::StringPiece16(kTest2, std::size(kTest2)),
&fallback_font));
// NUL only characters.
const char16_t kTest3[] = {0, 0, 0};
EXPECT_FALSE(GetFallbackFont(base_font, kDefaultApplicationLocale,
- base::StringPiece16(kTest3, base::size(kTest3)),
+ base::StringPiece16(kTest3, std::size(kTest3)),
&fallback_font));
}
TEST_F(FontFallbackWinTest, CJKLocaleFallback) {
- // The uniscribe fallback used by win7 does not support locale.
- if (base::win::GetVersion() < base::win::Version::WIN10)
- return;
-
// Han unification is an effort to map multiple character sets of the CJK
// languages into a single set of unified characters. Han characters are a
// common feature of written Chinese (hanzi), Japanese (kanji), and Korean
diff --git a/ui/gfx/font_list.cc b/ui/gfx/font_list.cc
index 4155b8a..5108e9c 100644
--- a/ui/gfx/font_list.cc
+++ b/ui/gfx/font_list.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,6 +10,7 @@
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
+#include "build/build_config.h"
#include "third_party/skia/include/core/SkFontMgr.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "ui/gfx/font_list_impl.h"
@@ -25,13 +26,9 @@
LAZY_INSTANCE_INITIALIZER;
bool g_default_impl_initialized = false;
-bool IsFontFamilyAvailable(const std::string& family, SkFontMgr* fontManager) {
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
- return !!fontManager->legacyMakeTypeface(family.c_str(), SkFontStyle());
-#else
- sk_sp<SkFontStyleSet> set(fontManager->matchFamily(family.c_str()));
- return set && set->count();
-#endif
+bool IsFontFamilyAvailable(const std::string& family, SkFontMgr* font_manager) {
+ return !!sk_sp<SkTypeface>(
+ font_manager->matchFamilyStyle(family.c_str(), SkFontStyle()));
}
} // namespace
diff --git a/ui/gfx/font_list.h b/ui/gfx/font_list.h
index a0d96fa..e384632 100644
--- a/ui/gfx/font_list.h
+++ b/ui/gfx/font_list.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,7 +8,7 @@
#include <string>
#include <vector>
-#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
#include "ui/gfx/font.h"
#include "ui/gfx/gfx_export.h"
diff --git a/ui/gfx/font_list_impl.cc b/ui/gfx/font_list_impl.cc
index d805ee1..a97f627 100644
--- a/ui/gfx/font_list_impl.cc
+++ b/ui/gfx/font_list_impl.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/font_list_impl.h b/ui/gfx/font_list_impl.h
index d405288..fc9a83d 100644
--- a/ui/gfx/font_list_impl.h
+++ b/ui/gfx/font_list_impl.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/font_list_unittest.cc b/ui/gfx/font_list_unittest.cc
index 405bdd9..728d0fe 100644
--- a/ui/gfx/font_list_unittest.cc
+++ b/ui/gfx/font_list_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/font_names_testing.cc b/ui/gfx/font_names_testing.cc
index 86e4abb..d49267a 100644
--- a/ui/gfx/font_names_testing.cc
+++ b/ui/gfx/font_names_testing.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -22,29 +22,29 @@
dessert.
*/
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
const char kTestFontName[] = "Arimo";
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
const char kTestFontName[] = "sans-serif";
#else
const char kTestFontName[] = "Arial";
#endif
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
const char kSymbolFontName[] = "DejaVu Sans";
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
const char kSymbolFontName[] = "monospace";
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
const char kSymbolFontName[] = "Segoe UI Symbol";
#else
const char kSymbolFontName[] = "Symbol";
#endif
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
const char kCJKFontName[] = "Noto Sans CJK JP";
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
const char kCJKFontName[] = "serif";
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
const char kCJKFontName[] = "Heiti SC";
#else
const char kCJKFontName[] = "SimSun";
diff --git a/ui/gfx/font_names_testing.h b/ui/gfx/font_names_testing.h
index b4f7a9a..16f5e65 100644
--- a/ui/gfx/font_names_testing.h
+++ b/ui/gfx/font_names_testing.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/font_render_params.cc b/ui/gfx/font_render_params.cc
index 31799c8..7109eb9 100644
--- a/ui/gfx/font_render_params.cc
+++ b/ui/gfx/font_render_params.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/font_render_params.h b/ui/gfx/font_render_params.h
index 96508f2..9aeb464 100644
--- a/ui/gfx/font_render_params.h
+++ b/ui/gfx/font_render_params.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -109,7 +109,7 @@
const FontRenderParamsQuery& query,
std::string* family_out);
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
// Clears GetFontRenderParams()'s cache. Intended to be called by tests that are
// changing Fontconfig's configuration.
GFX_EXPORT void ClearFontRenderParamsCacheForTest();
@@ -118,8 +118,8 @@
// Gets the device scale factor to query the FontRenderParams.
GFX_EXPORT float GetFontRenderParamsDeviceScaleFactor();
-#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
- defined(OS_ANDROID) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || \
+ BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_FUCHSIA)
// Sets the device scale factor for FontRenderParams to decide
// if it should enable subpixel positioning.
GFX_EXPORT void SetFontRenderParamsDeviceScaleFactor(
diff --git a/ui/gfx/font_render_params_linux.cc b/ui/gfx/font_render_params_linux.cc
index 7e42a2e..6198dd9 100644
--- a/ui/gfx/font_render_params_linux.cc
+++ b/ui/gfx/font_render_params_linux.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,10 +11,9 @@
#include <memory>
#include "base/command_line.h"
-#include "base/containers/mru_cache.h"
+#include "base/containers/lru_cache.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/synchronization/lock.h"
@@ -22,10 +21,14 @@
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "ui/gfx/font.h"
+#include "ui/gfx/font_render_params_linux.h"
#include "ui/gfx/linux/fontconfig_util.h"
-#include "ui/gfx/skia_font_delegate.h"
#include "ui/gfx/switches.h"
+#if BUILDFLAG(IS_LINUX)
+#include "ui/linux/linux_ui.h"
+#endif
+
namespace gfx {
namespace {
@@ -78,9 +81,7 @@
// Cached result from a call to GetFontRenderParams().
struct QueryResult {
QueryResult(const FontRenderParams& params, const std::string& family)
- : params(params),
- family(family) {
- }
+ : params(params), family(family) {}
~QueryResult() {}
FontRenderParams params;
@@ -89,7 +90,7 @@
// Keyed by hashes of FontRenderParamQuery structs from
// HashFontRenderParamsQuery().
-typedef base::HashingMRUCache<std::string, QueryResult> Cache;
+typedef base::HashingLRUCache<std::string, QueryResult> Cache;
// A cache and the lock that must be held while accessing it.
// GetFontRenderParams() is called by both the UI thread and the sandbox IPC
@@ -104,8 +105,16 @@
base::LazyInstance<SynchronizedCache>::Leaky g_synchronized_cache =
LAZY_INSTANCE_INITIALIZER;
-// Queries Fontconfig for rendering settings and updates |params_out| and
-// |family_out| (if non-NULL). Returns false on failure.
+// Serialize |query| into a string value suitable for use as a cache key.
+std::string GetFontRenderParamsQueryKey(const FontRenderParamsQuery& query) {
+ return base::StringPrintf(
+ "%d|%d|%d|%d|%s|%f", query.pixel_size, query.point_size, query.style,
+ static_cast<int>(query.weight),
+ base::JoinString(query.families, ",").c_str(), query.device_scale_factor);
+}
+
+} // namespace
+
bool QueryFontconfig(const FontRenderParamsQuery& query,
FontRenderParams* params_out,
std::string* family_out) {
@@ -117,15 +126,16 @@
FcPatternAddBool(query_pattern.get(), FC_SCALABLE, FcTrue);
for (auto it = query.families.begin(); it != query.families.end(); ++it) {
- FcPatternAddString(query_pattern.get(),
- FC_FAMILY, reinterpret_cast<const FcChar8*>(it->c_str()));
+ FcPatternAddString(query_pattern.get(), FC_FAMILY,
+ reinterpret_cast<const FcChar8*>(it->c_str()));
}
if (query.pixel_size > 0)
FcPatternAddDouble(query_pattern.get(), FC_PIXEL_SIZE, query.pixel_size);
if (query.point_size > 0)
FcPatternAddInteger(query_pattern.get(), FC_SIZE, query.point_size);
if (query.style >= 0) {
- FcPatternAddInteger(query_pattern.get(), FC_SLANT,
+ FcPatternAddInteger(
+ query_pattern.get(), FC_SLANT,
(query.style & Font::ITALIC) ? FC_SLANT_ITALIC : FC_SLANT_ROMAN);
}
if (query.weight != Font::Weight::INVALID) {
@@ -172,16 +182,6 @@
return true;
}
-// Serialize |query| into a string value suitable for use as a cache key.
-std::string GetFontRenderParamsQueryKey(const FontRenderParamsQuery& query) {
- return base::StringPrintf(
- "%d|%d|%d|%d|%s|%f", query.pixel_size, query.point_size, query.style,
- static_cast<int>(query.weight),
- base::JoinString(query.families, ",").c_str(), query.device_scale_factor);
-}
-
-} // namespace
-
FontRenderParams GetFontRenderParams(const FontRenderParamsQuery& query,
std::string* family_out) {
TRACE_EVENT0("fonts", "gfx::GetFontRenderParams");
@@ -212,9 +212,10 @@
// Start with the delegate's settings, but let Fontconfig have the final say.
FontRenderParams params;
- const SkiaFontDelegate* delegate = SkiaFontDelegate::instance();
- if (delegate)
- params = delegate->GetDefaultFontRenderParams();
+#if BUILDFLAG(IS_LINUX)
+ if (const auto* linux_ui = ui::LinuxUi::instance())
+ params = linux_ui->GetDefaultFontRenderParams();
+#endif
QueryFontconfig(actual_query, ¶ms, family_out);
if (!params.antialiasing) {
// Cairo forces full hinting when antialiasing is disabled, since anything
@@ -225,15 +226,15 @@
params.subpixel_positioning = false;
} else if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableFontSubpixelPositioning)) {
-#if !BUILDFLAG(IS_CHROMEOS_ASH)
- params.subpixel_positioning = actual_query.device_scale_factor > 1.0f;
-#else
+#if BUILDFLAG(IS_CHROMEOS)
// We want to enable subpixel positioning for fractional dsf.
params.subpixel_positioning =
std::abs(std::round(actual_query.device_scale_factor) -
actual_query.device_scale_factor) >
std::numeric_limits<float>::epsilon();
-#endif // !BUILDFLAG(IS_CHROMEOS_ASH)
+#else
+ params.subpixel_positioning = actual_query.device_scale_factor > 1.0f;
+#endif // BUILDFLAG(IS_CHROMEOS)
// To enable subpixel positioning, we need to disable hinting.
if (params.subpixel_positioning)
diff --git a/ui/gfx/font_render_params_linux.h b/ui/gfx/font_render_params_linux.h
new file mode 100644
index 0000000..fa63c3d
--- /dev/null
+++ b/ui/gfx/font_render_params_linux.h
@@ -0,0 +1,20 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_FONT_RENDER_PARAMS_LINUX_H_
+#define UI_GFX_FONT_RENDER_PARAMS_LINUX_H_
+
+#include "ui/gfx/font_render_params.h"
+
+namespace gfx {
+
+// Queries Fontconfig for rendering settings and updates |params_out| and
+// |family_out| (if non-nullptr). Returns false on failure.
+GFX_EXPORT bool QueryFontconfig(const FontRenderParamsQuery& query,
+ FontRenderParams* params_out,
+ std::string* family_out);
+
+} // namespace gfx
+
+#endif // UI_GFX_FONT_RENDER_PARAMS_LINUX_H_
\ No newline at end of file
diff --git a/ui/gfx/font_render_params_linux_unittest.cc b/ui/gfx/font_render_params_linux_unittest.cc
index 240e68b..c53d273 100644
--- a/ui/gfx/font_render_params_linux_unittest.cc
+++ b/ui/gfx/font_render_params_linux_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,16 +9,16 @@
#include "base/check_op.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
#include "base/notreached.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/test_fonts/fontconfig_util_linux.h"
+#include "third_party/test_fonts/fontconfig/fontconfig_util_linux.h"
#include "ui/gfx/font.h"
#include "ui/gfx/linux/fontconfig_util.h"
-#include "ui/gfx/skia_font_delegate.h"
+#include "ui/linux/fake_linux_ui.h"
namespace gfx {
@@ -36,16 +36,16 @@
const char kFontconfigMatchPatternHeader[] = " <match target=\"pattern\">\n";
const char kFontconfigMatchFooter[] = " </match>\n";
-// Implementation of SkiaFontDelegate that returns a canned FontRenderParams
+// Implementation of LinuxUi that returns a canned FontRenderParams
// struct. This is used to isolate tests from the system's local configuration.
-class TestFontDelegate : public SkiaFontDelegate {
+class TestFontDelegate : public ui::FakeLinuxUi {
public:
- TestFontDelegate() {}
+ TestFontDelegate() = default;
TestFontDelegate(const TestFontDelegate&) = delete;
TestFontDelegate& operator=(const TestFontDelegate&) = delete;
- ~TestFontDelegate() override {}
+ ~TestFontDelegate() override = default;
void set_params(const FontRenderParams& params) { params_ = params; }
@@ -55,7 +55,7 @@
void GetDefaultFontDescription(std::string* family_out,
int* size_pixels_out,
int* style_out,
- Font::Weight* weight_out,
+ int* weight_out,
FontRenderParams* params_out) const override {
NOTIMPLEMENTED();
}
@@ -111,8 +111,7 @@
class FontRenderParamsTest : public testing::Test {
public:
FontRenderParamsTest() {
- original_font_delegate_ = SkiaFontDelegate::instance();
- SkiaFontDelegate::SetInstance(&test_font_delegate_);
+ ui::LinuxUi::SetInstance(&test_font_delegate_);
ClearFontRenderParamsCacheForTest();
// Create a new fontconfig configuration and load the default fonts
@@ -135,59 +134,54 @@
~FontRenderParamsTest() override {
OverrideGlobalFontConfigForTesting(original_config_);
- FcConfigDestroy(override_config_);
-
- SkiaFontDelegate::SetInstance(
- const_cast<SkiaFontDelegate*>(original_font_delegate_));
+ FcConfigDestroy(override_config_.ExtractAsDangling());
+ ui::LinuxUi::SetInstance(old_linux_ui_);
}
protected:
- const SkiaFontDelegate* original_font_delegate_;
TestFontDelegate test_font_delegate_;
-
- FcConfig* override_config_ = nullptr;
- FcConfig* original_config_ = nullptr;
+ raw_ptr<ui::LinuxUi> old_linux_ui_ = nullptr;
+ raw_ptr<FcConfig> override_config_ = nullptr;
+ raw_ptr<FcConfig> original_config_ = nullptr;
};
TEST_F(FontRenderParamsTest, Default) {
ASSERT_TRUE(LoadConfigDataIntoFontconfig(
std::string(kFontconfigFileHeader) +
- // Specify the desired defaults via a font match rather than a pattern
- // match (since this is the style generally used in
- // /etc/fonts/conf.d).
- kFontconfigMatchFontHeader +
- CreateFontconfigEditStanza("antialias", "bool", "true") +
- CreateFontconfigEditStanza("autohint", "bool", "true") +
- CreateFontconfigEditStanza("hinting", "bool", "true") +
- CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
- CreateFontconfigEditStanza("rgba", "const", "rgb") +
- kFontconfigMatchFooter +
- // Add a font match for Arimo. Since it specifies a family, it
- // shouldn't take effect when querying default settings.
- kFontconfigMatchFontHeader +
- CreateFontconfigTestStanza("family", "eq", "string", "Arimo") +
- CreateFontconfigEditStanza("antialias", "bool", "true") +
- CreateFontconfigEditStanza("autohint", "bool", "false") +
- CreateFontconfigEditStanza("hinting", "bool", "true") +
- CreateFontconfigEditStanza("hintstyle", "const", "hintfull") +
- CreateFontconfigEditStanza("rgba", "const", "none") +
- kFontconfigMatchFooter +
- // Add font matches for fonts between 10 and 20 points or pixels.
- // Since they specify sizes, they also should not affect the defaults.
- kFontconfigMatchFontHeader +
- CreateFontconfigTestStanza("size", "more_eq", "double", "10.0") +
- CreateFontconfigTestStanza("size", "less_eq", "double", "20.0") +
- CreateFontconfigEditStanza("antialias", "bool", "false") +
- kFontconfigMatchFooter + kFontconfigMatchFontHeader +
- CreateFontconfigTestStanza("pixel_size", "more_eq", "double",
- "10.0") +
- CreateFontconfigTestStanza("pixel_size", "less_eq", "double",
- "20.0") +
- CreateFontconfigEditStanza("antialias", "bool", "false") +
- kFontconfigMatchFooter + kFontconfigFileFooter));
+ // Specify the desired defaults via a font match rather than a pattern
+ // match (since this is the style generally used in
+ // /etc/fonts/conf.d).
+ kFontconfigMatchFontHeader +
+ CreateFontconfigEditStanza("antialias", "bool", "true") +
+ CreateFontconfigEditStanza("autohint", "bool", "true") +
+ CreateFontconfigEditStanza("hinting", "bool", "true") +
+ CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
+ CreateFontconfigEditStanza("rgba", "const", "rgb") +
+ kFontconfigMatchFooter +
+ // Add a font match for Arimo. Since it specifies a family, it
+ // shouldn't take effect when querying default settings.
+ kFontconfigMatchFontHeader +
+ CreateFontconfigTestStanza("family", "eq", "string", "Arimo") +
+ CreateFontconfigEditStanza("antialias", "bool", "true") +
+ CreateFontconfigEditStanza("autohint", "bool", "false") +
+ CreateFontconfigEditStanza("hinting", "bool", "true") +
+ CreateFontconfigEditStanza("hintstyle", "const", "hintfull") +
+ CreateFontconfigEditStanza("rgba", "const", "none") +
+ kFontconfigMatchFooter +
+ // Add font matches for fonts between 10 and 20 points or pixels.
+ // Since they specify sizes, they also should not affect the defaults.
+ kFontconfigMatchFontHeader +
+ CreateFontconfigTestStanza("size", "more_eq", "double", "10.0") +
+ CreateFontconfigTestStanza("size", "less_eq", "double", "20.0") +
+ CreateFontconfigEditStanza("antialias", "bool", "false") +
+ kFontconfigMatchFooter + kFontconfigMatchFontHeader +
+ CreateFontconfigTestStanza("pixel_size", "more_eq", "double", "10.0") +
+ CreateFontconfigTestStanza("pixel_size", "less_eq", "double", "20.0") +
+ CreateFontconfigEditStanza("antialias", "bool", "false") +
+ kFontconfigMatchFooter + kFontconfigFileFooter));
- FontRenderParams params = GetFontRenderParams(
- FontRenderParamsQuery(), NULL);
+ FontRenderParams params =
+ GetFontRenderParams(FontRenderParamsQuery(), nullptr);
EXPECT_TRUE(params.antialiasing);
EXPECT_TRUE(params.autohinter);
EXPECT_TRUE(params.use_bitmaps);
@@ -200,31 +194,31 @@
TEST_F(FontRenderParamsTest, Size) {
ASSERT_TRUE(LoadConfigDataIntoFontconfig(
std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
- CreateFontconfigEditStanza("antialias", "bool", "true") +
- CreateFontconfigEditStanza("hinting", "bool", "true") +
- CreateFontconfigEditStanza("hintstyle", "const", "hintfull") +
- CreateFontconfigEditStanza("rgba", "const", "none") +
- kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
- CreateFontconfigTestStanza("pixelsize", "less_eq", "double", "10") +
- CreateFontconfigEditStanza("antialias", "bool", "false") +
- kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
- CreateFontconfigTestStanza("size", "more_eq", "double", "20") +
- CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
- CreateFontconfigEditStanza("rgba", "const", "rgb") +
- kFontconfigMatchFooter + kFontconfigFileFooter));
+ CreateFontconfigEditStanza("antialias", "bool", "true") +
+ CreateFontconfigEditStanza("hinting", "bool", "true") +
+ CreateFontconfigEditStanza("hintstyle", "const", "hintfull") +
+ CreateFontconfigEditStanza("rgba", "const", "none") +
+ kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
+ CreateFontconfigTestStanza("pixelsize", "less_eq", "double", "10") +
+ CreateFontconfigEditStanza("antialias", "bool", "false") +
+ kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
+ CreateFontconfigTestStanza("size", "more_eq", "double", "20") +
+ CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
+ CreateFontconfigEditStanza("rgba", "const", "rgb") +
+ kFontconfigMatchFooter + kFontconfigFileFooter));
// The defaults should be used when the supplied size isn't matched by the
// second or third blocks.
FontRenderParamsQuery query;
query.pixel_size = 12;
- FontRenderParams params = GetFontRenderParams(query, NULL);
+ FontRenderParams params = GetFontRenderParams(query, nullptr);
EXPECT_TRUE(params.antialiasing);
EXPECT_EQ(FontRenderParams::HINTING_FULL, params.hinting);
EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE,
params.subpixel_rendering);
query.pixel_size = 10;
- params = GetFontRenderParams(query, NULL);
+ params = GetFontRenderParams(query, nullptr);
EXPECT_FALSE(params.antialiasing);
EXPECT_EQ(FontRenderParams::HINTING_FULL, params.hinting);
EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE,
@@ -232,7 +226,7 @@
query.pixel_size = 0;
query.point_size = 20;
- params = GetFontRenderParams(query, NULL);
+ params = GetFontRenderParams(query, nullptr);
EXPECT_TRUE(params.antialiasing);
EXPECT_EQ(FontRenderParams::HINTING_SLIGHT, params.hinting);
EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_RGB,
@@ -244,41 +238,41 @@
// hinting for italic text.
ASSERT_TRUE(LoadConfigDataIntoFontconfig(
std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
- CreateFontconfigEditStanza("antialias", "bool", "true") +
- CreateFontconfigEditStanza("hinting", "bool", "true") +
- CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
- CreateFontconfigEditStanza("rgba", "const", "rgb") +
- kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
- CreateFontconfigTestStanza("weight", "eq", "const", "bold") +
- CreateFontconfigEditStanza("rgba", "const", "none") +
- kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
- CreateFontconfigTestStanza("slant", "eq", "const", "italic") +
- CreateFontconfigEditStanza("hinting", "bool", "false") +
- kFontconfigMatchFooter + kFontconfigFileFooter));
+ CreateFontconfigEditStanza("antialias", "bool", "true") +
+ CreateFontconfigEditStanza("hinting", "bool", "true") +
+ CreateFontconfigEditStanza("hintstyle", "const", "hintslight") +
+ CreateFontconfigEditStanza("rgba", "const", "rgb") +
+ kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
+ CreateFontconfigTestStanza("weight", "eq", "const", "bold") +
+ CreateFontconfigEditStanza("rgba", "const", "none") +
+ kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
+ CreateFontconfigTestStanza("slant", "eq", "const", "italic") +
+ CreateFontconfigEditStanza("hinting", "bool", "false") +
+ kFontconfigMatchFooter + kFontconfigFileFooter));
FontRenderParamsQuery query;
query.style = Font::NORMAL;
- FontRenderParams params = GetFontRenderParams(query, NULL);
+ FontRenderParams params = GetFontRenderParams(query, nullptr);
EXPECT_EQ(FontRenderParams::HINTING_SLIGHT, params.hinting);
EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_RGB,
params.subpixel_rendering);
query.weight = Font::Weight::BOLD;
- params = GetFontRenderParams(query, NULL);
+ params = GetFontRenderParams(query, nullptr);
EXPECT_EQ(FontRenderParams::HINTING_SLIGHT, params.hinting);
EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE,
params.subpixel_rendering);
query.weight = Font::Weight::NORMAL;
query.style = Font::ITALIC;
- params = GetFontRenderParams(query, NULL);
+ params = GetFontRenderParams(query, nullptr);
EXPECT_EQ(FontRenderParams::HINTING_NONE, params.hinting);
EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_RGB,
params.subpixel_rendering);
query.weight = Font::Weight::BOLD;
query.style = Font::ITALIC;
- params = GetFontRenderParams(query, NULL);
+ params = GetFontRenderParams(query, nullptr);
EXPECT_EQ(FontRenderParams::HINTING_NONE, params.hinting);
EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE,
params.subpixel_rendering);
@@ -288,15 +282,15 @@
// Load a config that only enables antialiasing for scalable fonts.
ASSERT_TRUE(LoadConfigDataIntoFontconfig(
std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
- CreateFontconfigEditStanza("antialias", "bool", "false") +
- kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
- CreateFontconfigTestStanza("scalable", "eq", "bool", "true") +
- CreateFontconfigEditStanza("antialias", "bool", "true") +
- kFontconfigMatchFooter + kFontconfigFileFooter));
+ CreateFontconfigEditStanza("antialias", "bool", "false") +
+ kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
+ CreateFontconfigTestStanza("scalable", "eq", "bool", "true") +
+ CreateFontconfigEditStanza("antialias", "bool", "true") +
+ kFontconfigMatchFooter + kFontconfigFileFooter));
// Check that we specifically ask how scalable fonts should be rendered.
- FontRenderParams params = GetFontRenderParams(
- FontRenderParamsQuery(), NULL);
+ FontRenderParams params =
+ GetFontRenderParams(FontRenderParamsQuery(), nullptr);
EXPECT_TRUE(params.antialiasing);
}
@@ -304,18 +298,18 @@
// Load a config that enables embedded bitmaps for fonts <= 10 pixels.
ASSERT_TRUE(LoadConfigDataIntoFontconfig(
std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
- CreateFontconfigEditStanza("embeddedbitmap", "bool", "false") +
- kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
- CreateFontconfigTestStanza("pixelsize", "less_eq", "double", "10") +
- CreateFontconfigEditStanza("embeddedbitmap", "bool", "true") +
- kFontconfigMatchFooter + kFontconfigFileFooter));
+ CreateFontconfigEditStanza("embeddedbitmap", "bool", "false") +
+ kFontconfigMatchFooter + kFontconfigMatchPatternHeader +
+ CreateFontconfigTestStanza("pixelsize", "less_eq", "double", "10") +
+ CreateFontconfigEditStanza("embeddedbitmap", "bool", "true") +
+ kFontconfigMatchFooter + kFontconfigFileFooter));
FontRenderParamsQuery query;
- FontRenderParams params = GetFontRenderParams(query, NULL);
+ FontRenderParams params = GetFontRenderParams(query, nullptr);
EXPECT_FALSE(params.use_bitmaps);
query.pixel_size = 5;
- params = GetFontRenderParams(query, NULL);
+ params = GetFontRenderParams(query, nullptr);
EXPECT_TRUE(params.use_bitmaps);
}
@@ -324,16 +318,16 @@
// subpixel rendering.
ASSERT_TRUE(LoadConfigDataIntoFontconfig(
std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
- CreateFontconfigEditStanza("antialias", "bool", "false") +
- CreateFontconfigEditStanza("hinting", "bool", "false") +
- CreateFontconfigEditStanza("hintstyle", "const", "hintnone") +
- CreateFontconfigEditStanza("rgba", "const", "rgb") +
- kFontconfigMatchFooter + kFontconfigFileFooter));
+ CreateFontconfigEditStanza("antialias", "bool", "false") +
+ CreateFontconfigEditStanza("hinting", "bool", "false") +
+ CreateFontconfigEditStanza("hintstyle", "const", "hintnone") +
+ CreateFontconfigEditStanza("rgba", "const", "rgb") +
+ kFontconfigMatchFooter + kFontconfigFileFooter));
// Full hinting should be forced. See the comment in GetFontRenderParams() for
// more information.
- FontRenderParams params = GetFontRenderParams(
- FontRenderParamsQuery(), NULL);
+ FontRenderParams params =
+ GetFontRenderParams(FontRenderParamsQuery(), nullptr);
EXPECT_FALSE(params.antialiasing);
EXPECT_EQ(FontRenderParams::HINTING_FULL, params.hinting);
EXPECT_EQ(FontRenderParams::SUBPIXEL_RENDERING_NONE,
@@ -344,7 +338,7 @@
TEST_F(FontRenderParamsTest, ForceSubpixelPositioning) {
{
FontRenderParams params =
- GetFontRenderParams(FontRenderParamsQuery(), NULL);
+ GetFontRenderParams(FontRenderParamsQuery(), nullptr);
EXPECT_TRUE(params.antialiasing);
EXPECT_FALSE(params.subpixel_positioning);
SetFontRenderParamsDeviceScaleFactor(1.0f);
@@ -354,7 +348,7 @@
// Subpixel positioning should be forced.
{
FontRenderParams params =
- GetFontRenderParams(FontRenderParamsQuery(), NULL);
+ GetFontRenderParams(FontRenderParamsQuery(), nullptr);
EXPECT_TRUE(params.antialiasing);
EXPECT_TRUE(params.subpixel_positioning);
SetFontRenderParamsDeviceScaleFactor(1.0f);
@@ -377,8 +371,7 @@
}
TEST_F(FontRenderParamsTest, OnlySetConfiguredValues) {
- // Configure the SkiaFontDelegate (which queries GtkSettings on desktop
- // Linux) to request subpixel rendering.
+ // Configure the LinuxUi to request subpixel rendering.
FontRenderParams system_params;
system_params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_RGB;
test_font_delegate_.set_params(system_params);
@@ -387,12 +380,12 @@
// about subpixel rendering.
ASSERT_TRUE(LoadConfigDataIntoFontconfig(
std::string(kFontconfigFileHeader) + kFontconfigMatchPatternHeader +
- CreateFontconfigEditStanza("antialias", "bool", "true") +
- kFontconfigMatchFooter + kFontconfigFileFooter));
+ CreateFontconfigEditStanza("antialias", "bool", "true") +
+ kFontconfigMatchFooter + kFontconfigFileFooter));
// The subpixel rendering setting from the delegate should make it through.
- FontRenderParams params = GetFontRenderParams(
- FontRenderParamsQuery(), NULL);
+ FontRenderParams params =
+ GetFontRenderParams(FontRenderParamsQuery(), nullptr);
EXPECT_EQ(system_params.subpixel_rendering, params.subpixel_rendering);
}
@@ -440,11 +433,11 @@
// Configure Fontconfig to use Tinos for both Helvetica and Arimo.
ASSERT_TRUE(LoadConfigDataIntoFontconfig(
std::string(kFontconfigFileHeader) +
- CreateFontconfigAliasStanza("Helvetica", "Tinos") +
- kFontconfigMatchPatternHeader +
- CreateFontconfigTestStanza("family", "eq", "string", "Arimo") +
- CreateFontconfigEditStanza("family", "string", "Tinos") +
- kFontconfigMatchFooter + kFontconfigFileFooter));
+ CreateFontconfigAliasStanza("Helvetica", "Tinos") +
+ kFontconfigMatchPatternHeader +
+ CreateFontconfigTestStanza("family", "eq", "string", "Arimo") +
+ CreateFontconfigEditStanza("family", "string", "Tinos") +
+ kFontconfigMatchFooter + kFontconfigFileFooter));
FontRenderParamsQuery query;
query.families.push_back("Helvetica");
diff --git a/ui/gfx/font_render_params_mac.cc b/ui/gfx/font_render_params_mac.cc
index 03bf988..86111a9 100644
--- a/ui/gfx/font_render_params_mac.cc
+++ b/ui/gfx/font_render_params_mac.cc
@@ -1,11 +1,12 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/font_render_params.h"
-#include "base/macros.h"
+#include "base/feature_list.h"
#include "base/notreached.h"
+#include "ui/base/ui_base_features.h"
namespace gfx {
@@ -17,9 +18,16 @@
params.antialiasing = true;
params.autohinter = false;
params.use_bitmaps = true;
- params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_RGB;
params.subpixel_positioning = true;
- params.hinting = FontRenderParams::HINTING_MEDIUM;
+
+ if (features::IsChromeRefresh2023() &&
+ !base::FeatureList::IsEnabled(features::kCr2023MacFontSmoothing)) {
+ params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_NONE;
+ params.hinting = FontRenderParams::HINTING_NONE;
+ } else {
+ params.subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_RGB;
+ params.hinting = FontRenderParams::HINTING_MEDIUM;
+ }
return params;
}
diff --git a/ui/gfx/font_render_params_skia.cc b/ui/gfx/font_render_params_skia.cc
index 7e8edf7..682c246 100644
--- a/ui/gfx/font_render_params_skia.cc
+++ b/ui/gfx/font_render_params_skia.cc
@@ -1,10 +1,9 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/font_render_params.h"
-#include "base/macros.h"
#include "base/notreached.h"
namespace gfx {
diff --git a/ui/gfx/font_render_params_win.cc b/ui/gfx/font_render_params_win.cc
index 1369f8a..4769c58 100644
--- a/ui/gfx/font_render_params_win.cc
+++ b/ui/gfx/font_render_params_win.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,10 +6,9 @@
#include <memory>
-#include "base/bind.h"
-#include "base/callback_helpers.h"
#include "base/files/file_path.h"
-#include "base/macros.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
#include "base/memory/singleton.h"
#include "base/win/registry.h"
#include "ui/gfx/win/singleton_hwnd_observer.h"
@@ -29,20 +28,34 @@
HKEY_LOCAL_MACHINE,
(L"SOFTWARE\\Microsoft\\Avalon.Graphics\\" + trimmed.value()).c_str(),
KEY_READ);
- DWORD pixel_structure;
- if (key.ReadValueDW(L"PixelStructure", &pixel_structure) ==
- ERROR_SUCCESS) {
- if (pixel_structure == 1)
- return FontRenderParams::SUBPIXEL_RENDERING_RGB;
- if (pixel_structure == 2)
- return FontRenderParams::SUBPIXEL_RENDERING_BGR;
+ DWORD structure;
+ if (key.ReadValueDW(L"PixelStructure", &structure) == ERROR_SUCCESS) {
+ switch (structure) {
+ case 0:
+ return FontRenderParams::SUBPIXEL_RENDERING_NONE;
+ case 1:
+ return FontRenderParams::SUBPIXEL_RENDERING_RGB;
+ case 2:
+ return FontRenderParams::SUBPIXEL_RENDERING_BGR;
+ }
+ return FontRenderParams::SUBPIXEL_RENDERING_NONE;
}
break;
}
}
- // No explicit ClearType settings, default to RGB.
- return FontRenderParams::SUBPIXEL_RENDERING_RGB;
+ UINT structure = 0;
+ if (SystemParametersInfo(SPI_GETFONTSMOOTHINGORIENTATION, 0, &structure, 0)) {
+ switch (structure) {
+ case FE_FONTSMOOTHINGORIENTATIONRGB:
+ return FontRenderParams::SUBPIXEL_RENDERING_RGB;
+ case FE_FONTSMOOTHINGORIENTATIONBGR:
+ return FontRenderParams::SUBPIXEL_RENDERING_BGR;
+ }
+ }
+
+ // No explicit ClearType settings, default to none.
+ return FontRenderParams::SUBPIXEL_RENDERING_NONE;
}
// Caches font render params and updates them on system notifications.
diff --git a/ui/gfx/font_unittest.cc b/ui/gfx/font_unittest.cc
index c71929d..5446115 100644
--- a/ui/gfx/font_unittest.cc
+++ b/ui/gfx/font_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,14 +6,13 @@
#include <string>
-#include "base/macros.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/font_names_testing.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "ui/gfx/system_fonts_win.h"
#endif
@@ -29,7 +28,7 @@
protected:
void SetUp() override {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// System fonts is keeping a cache of loaded system fonts. These fonts are
// scaled based on global callbacks configured on startup. The tests in this
// file are testing these callbacks and need to be sure we cleared the
@@ -54,8 +53,8 @@
TEST_F(FontTest, LoadArial) {
Font cf(kTestFontName, 16);
-#if defined(OS_APPLE)
- EXPECT_TRUE(cf.GetNativeFont());
+#if BUILDFLAG(IS_APPLE)
+ EXPECT_TRUE(cf.GetCTFont());
#endif
EXPECT_EQ(cf.GetStyle(), Font::NORMAL);
EXPECT_EQ(cf.GetFontSize(), 16);
@@ -67,8 +66,8 @@
TEST_F(FontTest, LoadArialBold) {
Font cf(kTestFontName, 16);
Font bold(cf.Derive(0, Font::NORMAL, Font::Weight::BOLD));
-#if defined(OS_APPLE)
- EXPECT_TRUE(bold.GetNativeFont());
+#if BUILDFLAG(IS_APPLE)
+ EXPECT_TRUE(bold.GetCTFont());
#endif
EXPECT_EQ(bold.GetStyle(), Font::NORMAL);
EXPECT_EQ(bold.GetWeight(), Font::Weight::BOLD);
@@ -144,7 +143,7 @@
EXPECT_EQ(cf.GetWeight(), cf_underlined_resized.GetWeight());
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
TEST_F(FontTest, DeriveResizesIfSizeTooSmall) {
Font cf(kTestFontName, 8);
gfx::win::SetGetMinimumFontSizeCallback([] { return 5; });
@@ -160,7 +159,7 @@
Font derived_font = cf.Derive(-2, cf.GetStyle(), cf.GetWeight());
EXPECT_EQ(6, derived_font.GetFontSize());
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
TEST_F(FontTest, WeightConversion) {
struct WeightMatchExpectation {
diff --git a/ui/gfx/font_util.cc b/ui/gfx/font_util.cc
index faf6dd7..6a2bf95 100644
--- a/ui/gfx/font_util.cc
+++ b/ui/gfx/font_util.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,12 +6,12 @@
#include "build/build_config.h"
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include <fontconfig/fontconfig.h>
#include "ui/gfx/linux/fontconfig_util.h"
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "ui/gfx/win/direct_write.h"
#endif
@@ -24,15 +24,15 @@
// background (resources have not yet been granted to cast) since it prevents
// the long delay the user would have seen on first rendering.
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
// Ensures the config is created on this thread.
FcConfig* config = GetGlobalFontConfig();
DCHECK(config);
-#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
gfx::win::InitializeDirectWrite();
-#endif // OS_WIN
+#endif // BUILDFLAG(IS_WIN)
}
} // namespace gfx
diff --git a/ui/gfx/font_util.h b/ui/gfx/font_util.h
index 0ceac62..b765018 100644
--- a/ui/gfx/font_util.h
+++ b/ui/gfx/font_util.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/frame_data.h b/ui/gfx/frame_data.h
new file mode 100644
index 0000000..a129402
--- /dev/null
+++ b/ui/gfx/frame_data.h
@@ -0,0 +1,27 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_FRAME_DATA_H_
+#define UI_GFX_FRAME_DATA_H_
+
+#include <cstdint>
+
+namespace gfx {
+
+// Contains per frame data, and is passed along with SwapBuffer, PostSubbuffer,
+// CommitOverlayPlanes type methods.
+struct FrameData {
+ explicit FrameData(int64_t seq = -1) : seq(seq) {}
+ ~FrameData() = default;
+
+ // Sequence number for this frame. The reserved value of -1 means that there
+ // is no sequence number specified (that is, corresponds to no sequence
+ // point). This may happen for some cases, like the ozone demo, tests, or
+ // users of GLSurface other than SkiaRenderer.
+ int64_t seq = -1;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_FRAME_DATA_H_
diff --git a/ui/gfx/gdi_util.cc b/ui/gfx/gdi_util.cc
index abfc3cb..576ba8d 100644
--- a/ui/gfx/gdi_util.cc
+++ b/ui/gfx/gdi_util.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/gdi_util.h b/ui/gfx/gdi_util.h
index 5b9af51..41c4288 100644
--- a/ui/gfx/gdi_util.h
+++ b/ui/gfx/gdi_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/generic_shared_memory_id.cc b/ui/gfx/generic_shared_memory_id.cc
index e9ed1c9..28378e7 100644
--- a/ui/gfx/generic_shared_memory_id.cc
+++ b/ui/gfx/generic_shared_memory_id.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/generic_shared_memory_id.h b/ui/gfx/generic_shared_memory_id.h
index 39c53e0..f355496 100644
--- a/ui/gfx/generic_shared_memory_id.h
+++ b/ui/gfx/generic_shared_memory_id.h
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -24,8 +24,9 @@
int id;
// Invalid ID is -1 to match semantics of base::AtomicSequenceNumber.
- GenericSharedMemoryId() : id(-1) {}
- explicit GenericSharedMemoryId(int id) : id(id) {}
+ constexpr GenericSharedMemoryId() : id(-1) {}
+ constexpr explicit GenericSharedMemoryId(int id) : id(id) {}
+
GenericSharedMemoryId(const GenericSharedMemoryId& other) = default;
GenericSharedMemoryId& operator=(const GenericSharedMemoryId& other) =
default;
diff --git a/ui/gfx/geometry/BUILD.gn b/ui/gfx/geometry/BUILD.gn
index abc446c..62cf2c0 100644
--- a/ui/gfx/geometry/BUILD.gn
+++ b/ui/gfx/geometry/BUILD.gn
@@ -1,28 +1,10 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
component("geometry") {
sources = [
- "../gfx_export.h",
- "angle_conversions.h",
- "axis_transform2d.cc",
- "axis_transform2d.h",
- "box_f.cc",
- "box_f.h",
- "cubic_bezier.cc",
- "cubic_bezier.h",
- "dip_util.cc",
- "dip_util.h",
"geometry_export.h",
- "insets.cc",
- "insets.h",
- "insets_conversions.cc",
- "insets_conversions.h",
- "insets_f.cc",
- "insets_f.h",
- "matrix3_f.cc",
- "matrix3_f.h",
"point.cc",
"point.h",
"point3_f.cc",
@@ -31,20 +13,8 @@
"point_conversions.h",
"point_f.cc",
"point_f.h",
- "quad_f.cc",
- "quad_f.h",
- "quaternion.cc",
- "quaternion.h",
"rect.cc",
"rect.h",
- "rect_conversions.cc",
- "rect_conversions.h",
- "rect_f.cc",
- "rect_f.h",
- "resize_utils.cc",
- "resize_utils.h",
- "rounded_corners_f.cc",
- "rounded_corners_f.h",
"size.cc",
"size.h",
"size_conversions.cc",
@@ -53,12 +23,8 @@
"size_f.h",
"vector2d.cc",
"vector2d.h",
- "vector2d_conversions.cc",
- "vector2d_conversions.h",
"vector2d_f.cc",
"vector2d_f.h",
- "vector3d_f.cc",
- "vector3d_f.h",
]
defines = [ "GEOMETRY_IMPLEMENTATION" ]
@@ -70,32 +36,3 @@
configs += [ "//build/config/compiler:optimize_max" ]
}
}
-
-component("geometry_skia") {
- sources = [
- "geometry_skia_export.h",
- "mask_filter_info.cc",
- "mask_filter_info.h",
- "rrect_f.cc",
- "rrect_f.h",
- "rrect_f_builder.cc",
- "rrect_f_builder.h",
- "skia_conversions.cc",
- "skia_conversions.h",
- "transform.cc",
- "transform.h",
- "transform_operation.cc",
- "transform_operation.h",
- "transform_operations.cc",
- "transform_operations.h",
- "transform_util.cc",
- "transform_util.h",
- ]
- configs += [ "//build/config/compiler:wexit_time_destructors" ]
- public_deps = [
- ":geometry",
- "//base",
- "//skia",
- ]
- defines = [ "GEOMETRY_SKIA_IMPLEMENTATION" ]
-}
diff --git a/ui/gfx/geometry/angle_conversions.h b/ui/gfx/geometry/angle_conversions.h
index 876ad5c..e21fc20 100644
--- a/ui/gfx/geometry/angle_conversions.h
+++ b/ui/gfx/geometry/angle_conversions.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/axis_transform2d.cc b/ui/gfx/geometry/axis_transform2d.cc
index fb2bb42..07b99ef 100644
--- a/ui/gfx/geometry/axis_transform2d.cc
+++ b/ui/gfx/geometry/axis_transform2d.cc
@@ -1,16 +1,38 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/axis_transform2d.h"
+#include "base/check_op.h"
#include "base/strings/stringprintf.h"
+#include "ui/gfx/geometry/decomposed_transform.h"
namespace gfx {
+DecomposedTransform AxisTransform2d::Decompose() const {
+ DecomposedTransform decomp;
+
+ decomp.translate[0] = translation_.x();
+ decomp.translate[1] = translation_.y();
+
+ if (scale_.x() >= 0 || scale_.y() >= 0) {
+ decomp.scale[0] = scale_.x();
+ decomp.scale[1] = scale_.y();
+ } else {
+ // If both scales are negative, decompose to positive scales with a 180deg
+ // rotation.
+ decomp.scale[0] = -scale_.x();
+ decomp.scale[1] = -scale_.y();
+ decomp.quaternion.set_z(1);
+ decomp.quaternion.set_w(0);
+ }
+ return decomp;
+}
+
std::string AxisTransform2d::ToString() const {
return base::StringPrintf("[%s, %s]", scale_.ToString().c_str(),
translation_.ToString().c_str());
}
-} // namespace gfx
\ No newline at end of file
+} // namespace gfx
diff --git a/ui/gfx/geometry/axis_transform2d.h b/ui/gfx/geometry/axis_transform2d.h
index 3e74fca..e950e82 100644
--- a/ui/gfx/geometry/axis_transform2d.h
+++ b/ui/gfx/geometry/axis_transform2d.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,30 +6,40 @@
#define UI_GFX_GEOMETRY_AXIS_TRANSFORM2D_H_
#include "base/check_op.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/geometry/clamp_float_geometry.h"
#include "ui/gfx/geometry/geometry_export.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/vector2d_f.h"
namespace gfx {
+struct DecomposedTransform;
+
// This class implements the subset of 2D linear transforms that only
// translation and uniform scaling are allowed.
// Internally this is stored as a vector for pre-scale, and another vector
// for post-translation. The class constructor and member accessor follows
// the same convention, but a scalar scale factor is also accepted.
+//
+// Results of the *Map* methods are clamped with ClampFloatGeometry().
+// See the definition of the function for details.
+//
class GEOMETRY_EXPORT AxisTransform2d {
public:
constexpr AxisTransform2d() = default;
constexpr AxisTransform2d(float scale, const Vector2dF& translation)
: scale_(scale, scale), translation_(translation) {}
- constexpr AxisTransform2d(const Vector2dF& scale,
- const Vector2dF& translation)
- : scale_(scale), translation_(translation) {}
+ static constexpr AxisTransform2d FromScaleAndTranslation(
+ const Vector2dF& scale,
+ const Vector2dF& translation) {
+ return AxisTransform2d(scale, translation);
+ }
- bool operator==(const AxisTransform2d& other) const {
+ constexpr bool operator==(const AxisTransform2d& other) const {
return scale_ == other.scale_ && translation_ == other.translation_;
}
- bool operator!=(const AxisTransform2d& other) const {
+ constexpr bool operator!=(const AxisTransform2d& other) const {
return !(*this == other);
}
@@ -54,37 +64,80 @@
PostTranslate(post.translation_);
}
+ double Determinant() const { return double{scale_.x()} * scale_.y(); }
+ bool IsInvertible() const {
+ // Check float determinant (stricter than checking each component or double
+ // determinant) to keep consistency with Matrix44.
+ // TODO(crbug.com/1359528): This may be stricter than necessary. Revisit
+ // this after combination of gfx::Transform and blink::TransformationMatrix.
+ return std::isnormal(scale_.x() * scale_.y());
+ }
void Invert() {
- DCHECK(scale_.x());
- DCHECK(scale_.y());
+ DCHECK(IsInvertible());
scale_ = Vector2dF(1.f / scale_.x(), 1.f / scale_.y());
translation_.Scale(-scale_.x(), -scale_.y());
}
+ // Changes the transform to: scale(z) * mat * scale(1/z).
+ // Useful for mapping zoomed points to their zoomed transformed result:
+ // new_mat * (scale(z) * x) == scale(z) * (mat * x).
+ void Zoom(float zoom_factor) { translation_.Scale(zoom_factor); }
+
PointF MapPoint(const PointF& p) const {
- return ScalePoint(p, scale_.x(), scale_.y()) + translation_;
+ return PointF(MapX(p.x()), MapY(p.y()));
}
PointF InverseMapPoint(const PointF& p) const {
- return ScalePoint(p - translation_, 1.f / scale_.x(), 1.f / scale_.y());
+ return PointF(InverseMapX(p.x()), InverseMapY(p.y()));
}
-
RectF MapRect(const RectF& r) const {
DCHECK_GE(scale_.x(), 0.f);
DCHECK_GE(scale_.y(), 0.f);
- return ScaleRect(r, scale_.x(), scale_.y()) + translation_;
+ return RectF(MapX(r.x()), MapY(r.y()),
+ ClampFloatGeometry(r.width() * scale_.x()),
+ ClampFloatGeometry(r.height() * scale_.y()));
}
RectF InverseMapRect(const RectF& r) const {
DCHECK_GT(scale_.x(), 0.f);
DCHECK_GT(scale_.y(), 0.f);
- return ScaleRect(r - translation_, 1.f / scale_.x(), 1.f / scale_.y());
+ return RectF(InverseMapX(r.x()), InverseMapY(r.y()),
+ // |* (1.f / scale)| instead of '/ scale' to keep the same
+ // precision before crrev.com/c/3937107.
+ ClampFloatGeometry(r.width() * (1.f / scale_.x())),
+ ClampFloatGeometry(r.height() * (1.f / scale_.y())));
}
- const Vector2dF& scale() const { return scale_; }
- const Vector2dF& translation() const { return translation_; }
+ // Decomposes this transform into |decomp|, following the 2d decomposition
+ // spec: https://www.w3.org/TR/css-transforms-1/#decomposing-a-2d-matrix.
+ // It's a simplified version of Matrix44::Decompose2d().
+ DecomposedTransform Decompose() const;
+
+ constexpr const Vector2dF& scale() const { return scale_; }
+ constexpr const Vector2dF& translation() const { return translation_; }
std::string ToString() const;
private:
+ constexpr AxisTransform2d(const Vector2dF& scale,
+ const Vector2dF& translation)
+ : scale_(scale), translation_(translation) {}
+
+ float MapX(float x) const {
+ return ClampFloatGeometry(x * scale_.x() + translation_.x());
+ }
+ float MapY(float y) const {
+ return ClampFloatGeometry(y * scale_.y() + translation_.y());
+ }
+ float InverseMapX(float x) const {
+ // |* (1.f / scale)| instead of '/ scale' to keep the same precision
+ // before crrev.com/c/3937107.
+ return ClampFloatGeometry((x - translation_.x()) * (1.f / scale_.x()));
+ }
+ float InverseMapY(float y) const {
+ // |* (1.f / scale)| instead of '/ scale' to keep the same precision
+ // before crrev.com/c/3937107.
+ return ClampFloatGeometry((y - translation_.y()) * (1.f / scale_.y()));
+ }
+
// Scale is applied before translation, i.e.
// this->Transform(p) == scale_ * p + translation_
Vector2dF scale_{1.f, 1.f};
diff --git a/ui/gfx/geometry/axis_transform2d_unittest.cc b/ui/gfx/geometry/axis_transform2d_unittest.cc
index 6bee3da..d8e5678 100644
--- a/ui/gfx/geometry/axis_transform2d_unittest.cc
+++ b/ui/gfx/geometry/axis_transform2d_unittest.cc
@@ -1,11 +1,13 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/axis_transform2d.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/test/gfx_util.h"
+#include "ui/gfx/geometry/decomposed_transform.h"
+#include "ui/gfx/geometry/test/geometry_util.h"
+#include "ui/gfx/geometry/transform.h"
namespace gfx {
namespace {
@@ -87,5 +89,95 @@
ConcatAxisTransform2d(inv_inplace, t));
}
+TEST(AxisTransform2dTest, ClampOutput) {
+ double entries[][2] = {
+ // The first entry is used to initialize the transform.
+ // The second entry is used to initialize the object to be mapped.
+ {std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::infinity()},
+ {1, std::numeric_limits<float>::infinity()},
+ {-1, std::numeric_limits<float>::infinity()},
+ {1, -std::numeric_limits<float>::infinity()},
+ {
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max(),
+ },
+ {
+ std::numeric_limits<float>::lowest(),
+ -std::numeric_limits<float>::infinity(),
+ },
+ };
+
+ for (double* entry : entries) {
+ const float mv = entry[0];
+ const float factor = entry[1];
+
+ auto is_valid_point = [&](const PointF& p) -> bool {
+ return std::isfinite(p.x()) && std::isfinite(p.y());
+ };
+ auto is_valid_rect = [&](const RectF& r) -> bool {
+ return is_valid_point(r.origin()) && std::isfinite(r.width()) &&
+ std::isfinite(r.height());
+ };
+
+ auto test = [&](const AxisTransform2d& m) {
+ SCOPED_TRACE(base::StringPrintf("m: %s factor: %lg", m.ToString().c_str(),
+ factor));
+ auto p = m.MapPoint(PointF(factor, factor));
+ EXPECT_TRUE(is_valid_point(p)) << p.ToString();
+
+ // AxisTransform2d::MapRect() requires non-negative scales.
+ if (m.scale().x() >= 0 && m.scale().y() >= 0) {
+ auto r = m.MapRect(RectF(factor, factor, factor, factor));
+ EXPECT_TRUE(is_valid_rect(r)) << r.ToString();
+ }
+ };
+
+ test(AxisTransform2d::FromScaleAndTranslation(Vector2dF(mv, mv),
+ Vector2dF(mv, mv)));
+ test(AxisTransform2d::FromScaleAndTranslation(Vector2dF(mv, mv),
+ Vector2dF(0, 0)));
+ test(AxisTransform2d::FromScaleAndTranslation(Vector2dF(1, 1),
+ Vector2dF(mv, mv)));
+ }
+}
+
+TEST(AxisTransform2dTest, Decompose) {
+ {
+ auto transform = AxisTransform2d::FromScaleAndTranslation(
+ Vector2dF(2.5, -3.75), Vector2dF(4.25, -5.5));
+ DecomposedTransform decomp = transform.Decompose();
+ EXPECT_DECOMPOSED_TRANSFORM_EQ((DecomposedTransform{{4.25, -5.5, 0},
+ {2.5, -3.75, 1},
+ {0, 0, 0},
+ {0, 0, 0, 1},
+ {0, 0, 0, 1}}),
+ decomp);
+ EXPECT_EQ(Transform(transform), Transform::Compose(decomp));
+ }
+ {
+ auto transform = AxisTransform2d::FromScaleAndTranslation(
+ Vector2dF(-2.5, -3.75), Vector2dF(4.25, -5.5));
+ DecomposedTransform decomp = transform.Decompose();
+ EXPECT_DECOMPOSED_TRANSFORM_EQ((DecomposedTransform{{4.25, -5.5, 0},
+ {2.5, 3.75, 1},
+ {0, 0, 0},
+ {0, 0, 0, 1},
+ {0, 0, 1, 0}}),
+ decomp);
+ EXPECT_EQ(Transform(transform), Transform::Compose(decomp));
+ }
+ {
+ auto transform =
+ AxisTransform2d::FromScaleAndTranslation(Vector2dF(), Vector2dF());
+ DecomposedTransform decomp = transform.Decompose();
+ EXPECT_DECOMPOSED_TRANSFORM_EQ(
+ (DecomposedTransform{
+ {0, 0, 0}, {0, 0, 1}, {0, 0, 0}, {0, 0, 0, 1}, {0, 0, 0, 1}}),
+ decomp);
+ EXPECT_EQ(Transform(transform), Transform::Compose(decomp));
+ }
+}
+
} // namespace
} // namespace gfx
diff --git a/ui/gfx/geometry/box_f.cc b/ui/gfx/geometry/box_f.cc
index d942b70..f09b803 100644
--- a/ui/gfx/geometry/box_f.cc
+++ b/ui/gfx/geometry/box_f.cc
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/box_f.h b/ui/gfx/geometry/box_f.h
index 443174d..0a7bc43 100644
--- a/ui/gfx/geometry/box_f.h
+++ b/ui/gfx/geometry/box_f.h
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/box_unittest.cc b/ui/gfx/geometry/box_unittest.cc
index 990fccc..8d0c9bd 100644
--- a/ui/gfx/geometry/box_unittest.cc
+++ b/ui/gfx/geometry/box_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/clamp_float_geometry.h b/ui/gfx/geometry/clamp_float_geometry.h
new file mode 100644
index 0000000..bb9f62e
--- /dev/null
+++ b/ui/gfx/geometry/clamp_float_geometry.h
@@ -0,0 +1,39 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_CLAMP_FLOAT_GEOMETRY_H_
+#define UI_GFX_GEOMETRY_CLAMP_FLOAT_GEOMETRY_H_
+
+#include <limits>
+
+#include "base/numerics/safe_conversions.h"
+
+namespace gfx {
+
+template <typename T>
+struct FloatGeometrySaturationHandler {
+ static constexpr float NaN() { return 0; }
+ static constexpr float Overflow() { return max(); }
+ static constexpr float Underflow() { return lowest(); }
+ static constexpr float max() {
+ return std::numeric_limits<float>::max() / 1e6;
+ }
+ static constexpr float lowest() {
+ return std::numeric_limits<float>::lowest() / 1e6;
+ }
+};
+
+// Clamps |value| (float, double or long double) within the range of
+// [numeric_limits<float>::lowest() / 1e6, numeric_limits<float::max() / 1e6f].
+// Returns 0 for NaN. This avoids NaN and infinity values immediately, and
+// reduce the chance of producing NaN and infinity values for future unclamped
+// operations like offsetting and scaling by devices / page scale factor.
+template <typename T>
+constexpr float ClampFloatGeometry(T value) {
+ return base::saturated_cast<float, FloatGeometrySaturationHandler, T>(value);
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_CLAMP_FLOAT_GEOMETRY_H_
diff --git a/ui/gfx/geometry/cubic_bezier.cc b/ui/gfx/geometry/cubic_bezier.cc
index ccd297b..d90a08c 100644
--- a/ui/gfx/geometry/cubic_bezier.cc
+++ b/ui/gfx/geometry/cubic_bezier.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,9 +6,9 @@
#include <algorithm>
#include <cmath>
+#include <limits>
#include "base/check_op.h"
-#include "base/cxx17_backports.h"
namespace gfx {
@@ -20,6 +20,17 @@
static const double kBezierEpsilon = 1e-7;
+double CubicBezier::ToFinite(double value) {
+ // TODO(crbug.com/1275541): We can clamp this in numeric operation helper
+ // function like ClampedNumeric.
+ if (std::isinf(value)) {
+ if (value > 0)
+ return std::numeric_limits<double>::max();
+ return std::numeric_limits<double>::lowest();
+ }
+ return value;
+}
+
CubicBezier::CubicBezier(double p1x, double p1y, double p2x, double p2y) {
InitCoefficients(p1x, p1y, p2x, p2y);
InitGradients(p1x, p1y, p2x, p2y);
@@ -39,9 +50,9 @@
bx_ = 3.0 * (p2x - p1x) - cx_;
ax_ = 1.0 - cx_ - bx_;
- cy_ = 3.0 * p1y;
- by_ = 3.0 * (p2y - p1y) - cy_;
- ay_ = 1.0 - cy_ - by_;
+ cy_ = ToFinite(3.0 * p1y);
+ by_ = ToFinite(3.0 * (p2y - p1y) - cy_);
+ ay_ = ToFinite(1.0 - cy_ - by_);
#ifndef NDEBUG
// Bezier curves with x-coordinates outside the range [0,1] for internal
@@ -229,11 +240,15 @@
}
double CubicBezier::SlopeWithEpsilon(double x, double epsilon) const {
- x = base::clamp(x, 0.0, 1.0);
+ x = std::clamp(x, 0.0, 1.0);
double t = SolveCurveX(x, epsilon);
double dx = SampleCurveDerivativeX(t);
double dy = SampleCurveDerivativeY(t);
- return dy / dx;
+ // TODO(crbug.com/1275534): We should clamp NaN to a proper value.
+ // Please see the issue for detail.
+ if (!dx && !dy)
+ return 0;
+ return ToFinite(dy / dx);
}
double CubicBezier::Slope(double x) const {
diff --git a/ui/gfx/geometry/cubic_bezier.h b/ui/gfx/geometry/cubic_bezier.h
index 5709888..efb9c34 100644
--- a/ui/gfx/geometry/cubic_bezier.h
+++ b/ui/gfx/geometry/cubic_bezier.h
@@ -1,11 +1,10 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_GEOMETRY_CUBIC_BEZIER_H_
#define UI_GFX_GEOMETRY_CUBIC_BEZIER_H_
-#include "base/macros.h"
#include "ui/gfx/geometry/geometry_export.h"
namespace gfx {
@@ -21,11 +20,14 @@
double SampleCurveX(double t) const {
// `ax t^3 + bx t^2 + cx t' expanded using Horner's rule.
+ // The x values are in the range [0, 1]. So it isn't needed toFinite
+ // clamping.
+ // https://drafts.csswg.org/css-easing-1/#funcdef-cubic-bezier-easing-function-cubic-bezier
return ((ax_ * t + bx_) * t + cx_) * t;
}
double SampleCurveY(double t) const {
- return ((ay_ * t + by_) * t + cy_) * t;
+ return ToFinite(((ay_ * t + by_) * t + cy_) * t);
}
double SampleCurveDerivativeX(double t) const {
@@ -33,7 +35,8 @@
}
double SampleCurveDerivativeY(double t) const {
- return (3.0 * ay_ * t + 2.0 * by_) * t + cy_;
+ return ToFinite(
+ ToFinite(ToFinite(3.0 * ay_) * t + ToFinite(2.0 * by_)) * t + cy_);
}
static double GetDefaultEpsilon();
@@ -49,9 +52,9 @@
// out of [0, 1] range.
double SolveWithEpsilon(double x, double epsilon) const {
if (x < 0.0)
- return 0.0 + start_gradient_ * x;
+ return ToFinite(0.0 + start_gradient_ * x);
if (x > 1.0)
- return 1.0 + end_gradient_ * (x - 1.0);
+ return ToFinite(1.0 + end_gradient_ * (x - 1.0));
return SampleCurveY(SolveCurveX(x, epsilon));
}
@@ -78,6 +81,7 @@
void InitGradients(double p1x, double p1y, double p2x, double p2y);
void InitRange(double p1y, double p2y);
void InitSpline();
+ static double ToFinite(double value);
double ax_;
double bx_;
diff --git a/ui/gfx/geometry/cubic_bezier_unittest.cc b/ui/gfx/geometry/cubic_bezier_unittest.cc
index bf86f41..37fbe2b 100644
--- a/ui/gfx/geometry/cubic_bezier_unittest.cc
+++ b/ui/gfx/geometry/cubic_bezier_unittest.cc
@@ -1,9 +1,10 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/cubic_bezier.h"
+#include <cmath>
#include <memory>
#include "testing/gtest/include/gtest/gtest.h"
@@ -76,6 +77,61 @@
EXPECT_NEAR(function.Solve(1.0), 1.0, epsilon);
}
+static void TestBezierFiniteRange(CubicBezier& function) {
+ for (double i = 0; i <= 1.01; i += 0.05) {
+ EXPECT_TRUE(std::isfinite(function.Solve(i)));
+ EXPECT_TRUE(std::isfinite(function.Slope(i)));
+ EXPECT_TRUE(std::isfinite(function.GetX2()));
+ EXPECT_TRUE(std::isfinite(function.GetY2()));
+ EXPECT_TRUE(std::isfinite(function.SampleCurveX(i)));
+ EXPECT_TRUE(std::isfinite(function.SampleCurveY(i)));
+ EXPECT_TRUE(std::isfinite(function.SampleCurveDerivativeX(i)));
+ EXPECT_TRUE(std::isfinite(function.SampleCurveDerivativeY(i)));
+ }
+}
+
+// Tests that solving the bezier works with huge value infinity evaluation
+TEST(CubicBezierTest, ClampInfinityEvaluation) {
+ auto test_cases = {
+ CubicBezier(0.5, std::numeric_limits<double>::max(), 0.5,
+ std::numeric_limits<double>::max()),
+ CubicBezier(0.5, std::numeric_limits<double>::lowest(), 0.5,
+ std::numeric_limits<double>::max()),
+ CubicBezier(0.5, std::numeric_limits<double>::max(), 0.5,
+ std::numeric_limits<double>::lowest()),
+ CubicBezier(0.5, std::numeric_limits<double>::lowest(), 0.5,
+ std::numeric_limits<double>::lowest()),
+
+ CubicBezier(0, std::numeric_limits<double>::max(), 0,
+ std::numeric_limits<double>::max()),
+ CubicBezier(0, std::numeric_limits<double>::lowest(), 0,
+ std::numeric_limits<double>::max()),
+ CubicBezier(0, std::numeric_limits<double>::max(), 0,
+ std::numeric_limits<double>::lowest()),
+ CubicBezier(0, std::numeric_limits<double>::lowest(), 0,
+ std::numeric_limits<double>::lowest()),
+
+ CubicBezier(1, std::numeric_limits<double>::max(), 1,
+ std::numeric_limits<double>::max()),
+ CubicBezier(1, std::numeric_limits<double>::lowest(), 1,
+ std::numeric_limits<double>::max()),
+ CubicBezier(1, std::numeric_limits<double>::max(), 1,
+ std::numeric_limits<double>::lowest()),
+ CubicBezier(1, std::numeric_limits<double>::lowest(), 1,
+ std::numeric_limits<double>::lowest()),
+
+ CubicBezier(0, 0, 0, std::numeric_limits<double>::max()),
+ CubicBezier(0, std::numeric_limits<double>::lowest(), 0, 0),
+ CubicBezier(1, 0, 0, std::numeric_limits<double>::lowest()),
+ CubicBezier(0, std::numeric_limits<double>::lowest(), 1, 1),
+
+ };
+
+ for (auto tc : test_cases) {
+ TestBezierFiniteRange(tc);
+ }
+}
+
TEST(CubicBezierTest, Range) {
double epsilon = 0.00015;
diff --git a/ui/gfx/geometry/decomposed_transform.cc b/ui/gfx/geometry/decomposed_transform.cc
new file mode 100644
index 0000000..572e742
--- /dev/null
+++ b/ui/gfx/geometry/decomposed_transform.cc
@@ -0,0 +1,26 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/decomposed_transform.h"
+
+#include <cstring>
+
+#include "base/strings/stringprintf.h"
+
+namespace gfx {
+
+std::string DecomposedTransform::ToString() const {
+ return base::StringPrintf(
+ "translate: %+lg %+lg %+lg\n"
+ "scale: %+lg %+lg %+lg\n"
+ "skew: %+lg %+lg %+lg\n"
+ "perspective: %+lg %+lg %+lg %+lg\n"
+ "quaternion: %+lg %+lg %+lg %+lg\n",
+ translate[0], translate[1], translate[2], scale[0], scale[1], scale[2],
+ skew[0], skew[1], skew[2], perspective[0], perspective[1], perspective[2],
+ perspective[3], quaternion.x(), quaternion.y(), quaternion.z(),
+ quaternion.w());
+}
+
+} // namespace gfx
diff --git a/ui/gfx/geometry/decomposed_transform.h b/ui/gfx/geometry/decomposed_transform.h
new file mode 100644
index 0000000..94435bd
--- /dev/null
+++ b/ui/gfx/geometry/decomposed_transform.h
@@ -0,0 +1,35 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_DECOMPOSED_TRANSFORM_H_
+#define UI_GFX_GEOMETRY_DECOMPOSED_TRANSFORM_H_
+
+#include "base/dcheck_is_on.h"
+#include "ui/gfx/geometry/geometry_export.h"
+#include "ui/gfx/geometry/quaternion.h"
+
+namespace gfx {
+
+// Contains the components of a factored transform. These components may be
+// blended and recomposed.
+struct GEOMETRY_EXPORT DecomposedTransform {
+ // The default constructor initializes the components in such a way that
+ // will compose the identity transform.
+ double translate[3] = {0, 0, 0};
+ double scale[3] = {1, 1, 1};
+ double skew[3] = {0, 0, 0};
+ double perspective[4] = {0, 0, 0, 1};
+ Quaternion quaternion;
+
+ std::string ToString() const;
+};
+
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const DecomposedTransform&, ::std::ostream* os);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_DECOMPOSED_TRANSFORM_H_
diff --git a/ui/gfx/geometry/dip_util.cc b/ui/gfx/geometry/dip_util.cc
index 11a15f7..db58be7 100644
--- a/ui/gfx/geometry/dip_util.cc
+++ b/ui/gfx/geometry/dip_util.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -17,152 +17,79 @@
namespace gfx {
-#if defined(OS_MAC)
-// Returns true if the floating point value is holding an integer, modulo
-// floating point error. The value `f` can be safely converted to its integer
-// form with base::ClampRound().
-static bool IsIntegerInFloat(float f) {
- return std::abs(f - base::ClampRound(f)) < 0.01f;
-}
-#endif
-
PointF ConvertPointToDips(const Point& point_in_pixels,
float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScalePoint(PointF(point_in_pixels), 1.f / device_scale_factor);
}
PointF ConvertPointToDips(const PointF& point_in_pixels,
float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScalePoint(point_in_pixels, 1.f / device_scale_factor);
}
PointF ConvertPointToPixels(const Point& point_in_dips,
float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScalePoint(PointF(point_in_dips), device_scale_factor);
}
PointF ConvertPointToPixels(const PointF& point_in_dips,
float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScalePoint(point_in_dips, device_scale_factor);
}
SizeF ConvertSizeToDips(const Size& size_in_pixels, float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScaleSize(SizeF(size_in_pixels), 1.f / device_scale_factor);
}
SizeF ConvertSizeToDips(const SizeF& size_in_pixels,
float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScaleSize(size_in_pixels, 1.f / device_scale_factor);
}
SizeF ConvertSizeToPixels(const Size& size_in_dips, float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScaleSize(SizeF(size_in_dips), device_scale_factor);
}
SizeF ConvertSizeToPixels(const SizeF& size_in_dips,
float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScaleSize(size_in_dips, device_scale_factor);
}
RectF ConvertRectToDips(const Rect& rect_in_pixels, float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScaleRect(RectF(rect_in_pixels), 1.f / device_scale_factor);
}
RectF ConvertRectToDips(const RectF& rect_in_pixels,
float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScaleRect(rect_in_pixels, 1.f / device_scale_factor);
}
RectF ConvertRectToPixels(const Rect& rect_in_dips, float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScaleRect(RectF(rect_in_dips), device_scale_factor);
}
RectF ConvertRectToPixels(const RectF& rect_in_dips,
float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScaleRect(rect_in_dips, device_scale_factor);
}
InsetsF ConvertInsetsToDips(const gfx::Insets& insets_in_pixels,
float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScaleInsets(InsetsF(insets_in_pixels), 1.f / device_scale_factor);
}
InsetsF ConvertInsetsToDips(const gfx::InsetsF& insets_in_pixels,
float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScaleInsets(insets_in_pixels, 1.f / device_scale_factor);
}
InsetsF ConvertInsetsToPixels(const gfx::Insets& insets_in_dips,
float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScaleInsets(InsetsF(insets_in_dips), device_scale_factor);
}
InsetsF ConvertInsetsToPixels(const gfx::InsetsF& insets_in_dips,
float device_scale_factor) {
-#if defined(OS_MAC)
- // Device scale factor on MacOSX is always an integer.
- DCHECK(IsIntegerInFloat(device_scale_factor));
-#endif
return ScaleInsets(insets_in_dips, device_scale_factor);
}
diff --git a/ui/gfx/geometry/dip_util.h b/ui/gfx/geometry/dip_util.h
index cc542a8..e46d200 100644
--- a/ui/gfx/geometry/dip_util.h
+++ b/ui/gfx/geometry/dip_util.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/double4.h b/ui/gfx/geometry/double4.h
new file mode 100644
index 0000000..72e8549
--- /dev/null
+++ b/ui/gfx/geometry/double4.h
@@ -0,0 +1,92 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_DOUBLE4_H_
+#define UI_GFX_GEOMETRY_DOUBLE4_H_
+
+#include <type_traits>
+
+namespace gfx {
+
+// This header defines Double4 type for vectorized SIMD operations used in
+// optimized transformation code. The type should be only used for local
+// variables, or inline function parameters or return values. Don't use the
+// type in other cases (e.g. for class data members) due to constraints
+// (e.g. alignment).
+//
+// Here are some examples of usages:
+//
+// double matrix[4][4] = ...;
+// // The scalar value will be applied to all components.
+// Double4 c0 = Load(matrix[0]) + 5;
+// Double4 c1 = Load(matrix[1]) * Double4{1, 2, 3, 4};
+//
+// Double4 v = c0 * c1;
+// // s0/s1/s2/s3 are preferred to x/y/z/w for consistency.
+// double a = v.s0 + Sum(c1);
+// // v.s3210 is equivalent to {v.s3, v.s2, v.s1, v.s0}.
+// // Should use this form instead of __builtin_shufflevector() etc.
+// Double4 swapped = {v[3], v[2], v[1], v[0]};
+//
+// // Logical operations.
+// bool b1 = AllTrue(swapped == c0);
+// // & is preferred to && to reduce branches.
+// bool b2 = AllTrue((c0 == c1) & (c0 == v) & (c0 >= swapped));
+//
+// Store(swapped, matrix_[2]);
+// Store(v, matrix_[3]);
+//
+// We use the gcc extension (supported by clang) instead of the clang extension
+// to make sure the code can compile with either gcc or clang.
+//
+// For more details, see
+// https://gcc.gnu.org/onlinedocs/gcc/Vector-Extensions.html
+
+#if !defined(__GNUC__) && !defined(__clang__)
+#error Unsupported compiler.
+#endif
+
+typedef double __attribute__((vector_size(4 * sizeof(double)))) Double4;
+typedef float __attribute__((vector_size(4 * sizeof(float)))) Float4;
+
+ALWAYS_INLINE double Sum(Double4 v) {
+ return v[0] + v[1] + v[2] + v[3];
+}
+
+ALWAYS_INLINE Double4 LoadDouble4(const double s[4]) {
+ return Double4{s[0], s[1], s[2], s[3]};
+}
+
+ALWAYS_INLINE void StoreDouble4(Double4 v, double d[4]) {
+ d[0] = v[0];
+ d[1] = v[1];
+ d[2] = v[2];
+ d[3] = v[3];
+}
+
+// The parameter should be the result of Double4/Float4 operations that would
+// produce bool results if they were original scalar operators, e.g.
+// auto b4 = double4_a == double4_b;
+// A zero value of a component of |b4| means false, otherwise true.
+// This function checks whether all 4 components in |b4| are true.
+// |&| instead of |&&| is used to avoid branches, which results shorter and
+// faster code in most cases. It's used like:
+// if (AllTrue(double4_a == double4_b))
+// ...
+// if (AllTrue((double4_a1 == double4_b1) & (double4_a2 == double4_b2)))
+// ...
+typedef int64_t __attribute__((vector_size(4 * sizeof(int64_t))))
+DoubleBoolean4;
+ALWAYS_INLINE int64_t AllTrue(DoubleBoolean4 b4) {
+ return b4[0] & b4[1] & b4[2] & b4[3];
+}
+
+typedef int32_t __attribute__((vector_size(4 * sizeof(int32_t)))) FloatBoolean4;
+ALWAYS_INLINE int32_t AllTrue(FloatBoolean4 b4) {
+ return b4[0] & b4[1] & b4[2] & b4[3];
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_DOUBLE4_H_
diff --git a/ui/gfx/geometry/geometry_export.h b/ui/gfx/geometry/geometry_export.h
index 5e68787..838b13e 100644
--- a/ui/gfx/geometry/geometry_export.h
+++ b/ui/gfx/geometry/geometry_export.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/geometry_skia_export.h b/ui/gfx/geometry/geometry_skia_export.h
index b7cda33..0b7bc70 100644
--- a/ui/gfx/geometry/geometry_skia_export.h
+++ b/ui/gfx/geometry/geometry_skia_export.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/insets.cc b/ui/gfx/geometry/insets.cc
index 0e706e1..9e43043 100644
--- a/ui/gfx/geometry/insets.cc
+++ b/ui/gfx/geometry/insets.cc
@@ -1,38 +1,40 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright 2009 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/insets.h"
-#include "base/strings/stringprintf.h"
#include "ui/gfx/geometry/insets_conversions.h"
#include "ui/gfx/geometry/insets_f.h"
+#include "ui/gfx/geometry/outsets.h"
#include "ui/gfx/geometry/vector2d.h"
namespace gfx {
-std::string Insets::ToString() const {
- // Print members in the same order of the constructor parameters.
- return base::StringPrintf("%d,%d,%d,%d", top(), left(), bottom(), right());
+Outsets Insets::ToOutsets() const {
+ // Conversion from Insets to Outsets negates all components.
+ return Outsets()
+ .set_left_right(-left(), -right())
+ .set_top_bottom(-top(), -bottom());
}
-Insets Insets::Offset(const gfx::Vector2d& vector) const {
- return gfx::Insets(base::ClampAdd(top(), vector.y()),
- base::ClampAdd(left(), vector.x()),
- base::ClampSub(bottom(), vector.y()),
- base::ClampSub(right(), vector.x()));
+void Insets::Offset(const gfx::Vector2d& vector) {
+ set_left_right(base::ClampAdd(left(), vector.x()),
+ base::ClampSub(right(), vector.x()));
+ set_top_bottom(base::ClampAdd(top(), vector.y()),
+ base::ClampSub(bottom(), vector.y()));
}
Insets ScaleToCeiledInsets(const Insets& insets, float x_scale, float y_scale) {
if (x_scale == 1.f && y_scale == 1.f)
return insets;
- return ToCeiledInsets(ScaleInsets(gfx::InsetsF(insets), x_scale, y_scale));
+ return ToCeiledInsets(ScaleInsets(InsetsF(insets), x_scale, y_scale));
}
Insets ScaleToCeiledInsets(const Insets& insets, float scale) {
if (scale == 1.f)
return insets;
- return ToCeiledInsets(ScaleInsets(gfx::InsetsF(insets), scale));
+ return ToCeiledInsets(ScaleInsets(InsetsF(insets), scale));
}
Insets ScaleToFlooredInsets(const Insets& insets,
@@ -40,13 +42,13 @@
float y_scale) {
if (x_scale == 1.f && y_scale == 1.f)
return insets;
- return ToFlooredInsets(ScaleInsets(gfx::InsetsF(insets), x_scale, y_scale));
+ return ToFlooredInsets(ScaleInsets(InsetsF(insets), x_scale, y_scale));
}
Insets ScaleToFlooredInsets(const Insets& insets, float scale) {
if (scale == 1.f)
return insets;
- return ToFlooredInsets(ScaleInsets(gfx::InsetsF(insets), scale));
+ return ToFlooredInsets(ScaleInsets(InsetsF(insets), scale));
}
Insets ScaleToRoundedInsets(const Insets& insets,
@@ -54,13 +56,13 @@
float y_scale) {
if (x_scale == 1.f && y_scale == 1.f)
return insets;
- return ToRoundedInsets(ScaleInsets(gfx::InsetsF(insets), x_scale, y_scale));
+ return ToRoundedInsets(ScaleInsets(InsetsF(insets), x_scale, y_scale));
}
Insets ScaleToRoundedInsets(const Insets& insets, float scale) {
if (scale == 1.f)
return insets;
- return ToRoundedInsets(ScaleInsets(gfx::InsetsF(insets), scale));
+ return ToRoundedInsets(ScaleInsets(InsetsF(insets), scale));
}
} // namespace gfx
diff --git a/ui/gfx/geometry/insets.h b/ui/gfx/geometry/insets.h
index 9d83dca..c4a3f16 100644
--- a/ui/gfx/geometry/insets.h
+++ b/ui/gfx/geometry/insets.h
@@ -1,175 +1,44 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_GEOMETRY_INSETS_H_
#define UI_GFX_GEOMETRY_INSETS_H_
-#include <string>
-
#include "base/numerics/clamped_math.h"
#include "ui/gfx/geometry/geometry_export.h"
#include "ui/gfx/geometry/insets_f.h"
-#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/insets_outsets_base.h"
namespace gfx {
+class Outsets;
class Vector2d;
-// Represents the widths of the four borders or margins of an unspecified
-// rectangle. An Insets stores the thickness of the top, left, bottom and right
-// edges, without storing the actual size and position of the rectangle itself.
-//
// This can be used to represent a space within a rectangle, by "shrinking" the
// rectangle by the inset amount on all four sides. Alternatively, it can
// represent a border that has a different thickness on each side.
-class GEOMETRY_EXPORT Insets {
+class GEOMETRY_EXPORT Insets : public InsetsOutsetsBase<Insets> {
public:
- constexpr Insets() : top_(0), left_(0), bottom_(0), right_(0) {}
- constexpr explicit Insets(int all)
- : top_(all),
- left_(all),
- bottom_(GetClampedValue(all, all)),
- right_(GetClampedValue(all, all)) {}
- constexpr explicit Insets(int vertical, int horizontal)
- : top_(vertical),
- left_(horizontal),
- bottom_(GetClampedValue(vertical, vertical)),
- right_(GetClampedValue(horizontal, horizontal)) {}
- constexpr Insets(int top, int left, int bottom, int right)
- : top_(top),
- left_(left),
- bottom_(GetClampedValue(top, bottom)),
- right_(GetClampedValue(left, right)) {}
+ using InsetsOutsetsBase::InsetsOutsetsBase;
- constexpr int top() const { return top_; }
- constexpr int left() const { return left_; }
- constexpr int bottom() const { return bottom_; }
- constexpr int right() const { return right_; }
-
- // Returns the total width taken up by the insets, which is the sum of the
- // left and right insets.
- constexpr int width() const { return left_ + right_; }
-
- // Returns the total height taken up by the insets, which is the sum of the
- // top and bottom insets.
- constexpr int height() const { return top_ + bottom_; }
-
- // Returns the sum of the left and right insets as the width, the sum of the
- // top and bottom insets as the height.
- constexpr Size size() const { return Size(width(), height()); }
-
- // Returns true if the insets are empty.
- bool IsEmpty() const { return width() == 0 && height() == 0; }
-
- void set_top(int top) {
- top_ = top;
- bottom_ = GetClampedValue(top_, bottom_);
- }
- void set_left(int left) {
- left_ = left;
- right_ = GetClampedValue(left_, right_);
- }
- void set_bottom(int bottom) { bottom_ = GetClampedValue(top_, bottom); }
- void set_right(int right) { right_ = GetClampedValue(left_, right); }
-
- void Set(int top, int left, int bottom, int right) {
- top_ = top;
- left_ = left;
- bottom_ = GetClampedValue(top_, bottom);
- right_ = GetClampedValue(left_, right);
- }
-
- bool operator==(const Insets& insets) const {
- return top_ == insets.top_ && left_ == insets.left_ &&
- bottom_ == insets.bottom_ && right_ == insets.right_;
- }
-
- bool operator!=(const Insets& insets) const {
- return !(*this == insets);
- }
-
- void operator+=(const Insets& insets) {
- top_ = base::ClampAdd(top_, insets.top_);
- left_ = base::ClampAdd(left_, insets.left_);
- bottom_ = GetClampedValue(top_, base::ClampAdd(bottom_, insets.bottom_));
- right_ = GetClampedValue(left_, base::ClampAdd(right_, insets.right_));
- }
-
- void operator-=(const Insets& insets) {
- top_ = base::ClampSub(top_, insets.top_);
- left_ = base::ClampSub(left_, insets.left_);
- bottom_ = GetClampedValue(top_, base::ClampSub(bottom_, insets.bottom_));
- right_ = GetClampedValue(left_, base::ClampSub(right_, insets.right_));
- }
-
- Insets operator-() const {
- return Insets(-base::MakeClampedNum(top_), -base::MakeClampedNum(left_),
- -base::MakeClampedNum(bottom_),
- -base::MakeClampedNum(right_));
- }
+ // Conversion from Insets to Outsets negates all components.
+ Outsets ToOutsets() const;
// Adjusts the vertical and horizontal dimensions by the values described in
// |vector|. Offsetting insets before applying to a rectangle would be
- // equivalent to offseting the rectangle then applying the insets.
- Insets Offset(const gfx::Vector2d& vector) const;
+ // equivalent to offsetting the rectangle then applying the insets.
+ void Offset(const gfx::Vector2d& vector);
- operator InsetsF() const {
- return InsetsF(static_cast<float>(top()), static_cast<float>(left()),
- static_cast<float>(bottom()), static_cast<float>(right()));
- }
-
- // Returns a string representation of the insets.
- std::string ToString() const;
-
- private:
- int top_;
- int left_;
- int bottom_;
- int right_;
-
- // See ui/gfx/geometry/rect.h
- // Returns true iff a+b would overflow max int.
- static constexpr bool AddWouldOverflow(int a, int b) {
- // In this function, GCC tries to make optimizations that would only work if
- // max - a wouldn't overflow but it isn't smart enough to notice that a > 0.
- // So cast everything to unsigned to avoid this. As it is guaranteed that
- // max - a and b are both already positive, the cast is a noop.
- //
- // This is intended to be: a > 0 && max - a < b
- return a > 0 && b > 0 &&
- static_cast<unsigned>(std::numeric_limits<int>::max() - a) <
- static_cast<unsigned>(b);
- }
-
- // Returns true iff a+b would underflow min int.
- static constexpr bool AddWouldUnderflow(int a, int b) {
- return a < 0 && b < 0 && std::numeric_limits<int>::min() - a > b;
- }
-
- // Clamp the right/bottom to avoid integer over/underflow in width() and
- // height(). This returns the right/bottom given a top_or_left and a
- // bottom_or_right.
- // TODO(enne): this should probably use base::ClampAdd, but that
- // function is not a constexpr.
- static constexpr int GetClampedValue(int top_or_left, int bottom_or_right) {
- if (AddWouldOverflow(top_or_left, bottom_or_right)) {
- return std::numeric_limits<int>::max() - top_or_left;
- } else if (AddWouldUnderflow(top_or_left, bottom_or_right)) {
- // If |top_or_left| and |bottom_or_right| are both negative,
- // adds |top_or_left| to prevent underflow by subtracting it.
- return std::numeric_limits<int>::min() - top_or_left;
- } else {
- return bottom_or_right;
- }
+ explicit operator InsetsF() const {
+ return InsetsF()
+ .set_top(static_cast<float>(top()))
+ .set_left(static_cast<float>(left()))
+ .set_bottom(static_cast<float>(bottom()))
+ .set_right(static_cast<float>(right()));
}
};
-// This is declared here for use in gtest-based unit tests but is defined in
-// the //ui/gfx:test_support target. Depend on that to use this in your unit
-// test. This should not be used in production code - call ToString() instead.
-void PrintTo(const Insets& point, ::std::ostream* os);
-
inline Insets operator+(Insets lhs, const Insets& rhs) {
lhs += rhs;
return lhs;
@@ -180,6 +49,11 @@
return lhs;
}
+inline Insets operator+(Insets insets, const gfx::Vector2d& offset) {
+ insets.Offset(offset);
+ return insets;
+}
+
// Helper methods to scale a gfx::Insets to a new gfx::Insets.
GEOMETRY_EXPORT Insets ScaleToCeiledInsets(const Insets& insets,
float x_scale,
@@ -194,6 +68,11 @@
float y_scale);
GEOMETRY_EXPORT Insets ScaleToRoundedInsets(const Insets& insets, float scale);
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const Insets&, ::std::ostream* os);
+
} // namespace gfx
#endif // UI_GFX_GEOMETRY_INSETS_H_
diff --git a/ui/gfx/geometry/insets_conversions.cc b/ui/gfx/geometry/insets_conversions.cc
index e41a600..70f488e 100644
--- a/ui/gfx/geometry/insets_conversions.cc
+++ b/ui/gfx/geometry/insets_conversions.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,21 +11,21 @@
namespace gfx {
Insets ToFlooredInsets(const InsetsF& insets) {
- return Insets(base::ClampFloor(insets.top()), base::ClampFloor(insets.left()),
- base::ClampFloor(insets.bottom()),
- base::ClampFloor(insets.right()));
+ return Insets::TLBR(
+ base::ClampFloor(insets.top()), base::ClampFloor(insets.left()),
+ base::ClampFloor(insets.bottom()), base::ClampFloor(insets.right()));
}
Insets ToCeiledInsets(const InsetsF& insets) {
- return Insets(base::ClampCeil(insets.top()), base::ClampCeil(insets.left()),
- base::ClampCeil(insets.bottom()),
- base::ClampCeil(insets.right()));
+ return Insets::TLBR(
+ base::ClampCeil(insets.top()), base::ClampCeil(insets.left()),
+ base::ClampCeil(insets.bottom()), base::ClampCeil(insets.right()));
}
Insets ToRoundedInsets(const InsetsF& insets) {
- return Insets(base::ClampRound(insets.top()), base::ClampRound(insets.left()),
- base::ClampRound(insets.bottom()),
- base::ClampRound(insets.right()));
+ return Insets::TLBR(
+ base::ClampRound(insets.top()), base::ClampRound(insets.left()),
+ base::ClampRound(insets.bottom()), base::ClampRound(insets.right()));
}
} // namespace gfx
diff --git a/ui/gfx/geometry/insets_conversions.h b/ui/gfx/geometry/insets_conversions.h
index 6135150..dbac49d 100644
--- a/ui/gfx/geometry/insets_conversions.h
+++ b/ui/gfx/geometry/insets_conversions.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/insets_f.cc b/ui/gfx/geometry/insets_f.cc
index c1bc27e..5818a3e 100644
--- a/ui/gfx/geometry/insets_f.cc
+++ b/ui/gfx/geometry/insets_f.cc
@@ -1,16 +1,20 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/insets_f.h"
-#include "base/strings/stringprintf.h"
+#include "ui/gfx/geometry/outsets_f.h"
namespace gfx {
-std::string InsetsF::ToString() const {
- // Print members in the same order of the constructor parameters.
- return base::StringPrintf("%f,%f,%f,%f", top(), left(), bottom(), right());
+OutsetsF InsetsF::ToOutsets() const {
+ // Conversion from InsetsF to OutsetsF negates all components.
+ return OutsetsF()
+ .set_left(-left())
+ .set_right(-right())
+ .set_top(-top())
+ .set_bottom(-bottom());
}
} // namespace gfx
diff --git a/ui/gfx/geometry/insets_f.h b/ui/gfx/geometry/insets_f.h
index 3d9380c..e43cc13 100644
--- a/ui/gfx/geometry/insets_f.h
+++ b/ui/gfx/geometry/insets_f.h
@@ -1,108 +1,33 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_GEOMETRY_INSETS_F_H_
#define UI_GFX_GEOMETRY_INSETS_F_H_
-#include <string>
-
#include "ui/gfx/geometry/geometry_export.h"
+#include "ui/gfx/geometry/insets_outsets_f_base.h"
namespace gfx {
+class OutsetsF;
+
// A floating point version of gfx::Insets.
-class GEOMETRY_EXPORT InsetsF {
+class GEOMETRY_EXPORT InsetsF : public InsetsOutsetsFBase<InsetsF> {
public:
- constexpr InsetsF() : top_(0.f), left_(0.f), bottom_(0.f), right_(0.f) {}
- constexpr explicit InsetsF(float all)
- : top_(all), left_(all), bottom_(all), right_(all) {}
- constexpr InsetsF(float vertical, float horizontal)
- : top_(vertical),
- left_(horizontal),
- bottom_(vertical),
- right_(horizontal) {}
- constexpr InsetsF(float top, float left, float bottom, float right)
- : top_(top), left_(left), bottom_(bottom), right_(right) {}
+ using InsetsOutsetsFBase::InsetsOutsetsFBase;
- constexpr float top() const { return top_; }
- constexpr float left() const { return left_; }
- constexpr float bottom() const { return bottom_; }
- constexpr float right() const { return right_; }
-
- // Returns the total width taken up by the insets, which is the sum of the
- // left and right insets.
- constexpr float width() const { return left_ + right_; }
-
- // Returns the total height taken up by the insets, which is the sum of the
- // top and bottom insets.
- constexpr float height() const { return top_ + bottom_; }
-
- // Returns true if the insets are empty.
- bool IsEmpty() const { return width() == 0.f && height() == 0.f; }
-
- void Set(float top, float left, float bottom, float right) {
- top_ = top;
- left_ = left;
- bottom_ = bottom;
- right_ = right;
- }
-
- bool operator==(const InsetsF& insets) const {
- return top_ == insets.top_ && left_ == insets.left_ &&
- bottom_ == insets.bottom_ && right_ == insets.right_;
- }
-
- bool operator!=(const InsetsF& insets) const {
- return !(*this == insets);
- }
-
- void operator+=(const InsetsF& insets) {
- top_ += insets.top_;
- left_ += insets.left_;
- bottom_ += insets.bottom_;
- right_ += insets.right_;
- }
-
- void operator-=(const InsetsF& insets) {
- top_ -= insets.top_;
- left_ -= insets.left_;
- bottom_ -= insets.bottom_;
- right_ -= insets.right_;
- }
-
- InsetsF operator-() const {
- return InsetsF(-top_, -left_, -bottom_, -right_);
- }
-
- InsetsF Scale(float scale) const {
- return InsetsF(scale * top(), scale * left(), scale * bottom(),
- scale * right());
- }
-
- // Returns a string representation of the insets.
- std::string ToString() const;
-
- private:
- float top_;
- float left_;
- float bottom_;
- float right_;
+ // Conversion from InsetsF to OutsetsF negates all components.
+ OutsetsF ToOutsets() const;
};
-// This is declared here for use in gtest-based unit tests but is defined in
-// the //ui/gfx:test_support target. Depend on that to use this in your unit
-// test. This should not be used in production code - call ToString() instead.
-void PrintTo(const InsetsF& point, ::std::ostream* os);
-
-inline InsetsF ScaleInsets(const InsetsF& i, float scale) {
- return InsetsF(i.top() * scale, i.left() * scale, i.bottom() * scale,
- i.right() * scale);
+inline InsetsF ScaleInsets(InsetsF i, float x_scale, float y_scale) {
+ i.Scale(x_scale, y_scale);
+ return i;
}
-inline InsetsF ScaleInsets(const InsetsF& i, float x_scale, float y_scale) {
- return InsetsF(i.top() * y_scale, i.left() * x_scale, i.bottom() * y_scale,
- i.right() * x_scale);
+inline InsetsF ScaleInsets(const InsetsF& i, float scale) {
+ return ScaleInsets(i, scale, scale);
}
inline InsetsF operator+(InsetsF lhs, const InsetsF& rhs) {
@@ -115,6 +40,11 @@
return lhs;
}
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const InsetsF&, ::std::ostream* os);
+
} // namespace gfx
#endif // UI_GFX_GEOMETRY_INSETS_F_H_
diff --git a/ui/gfx/geometry/insets_f_unittest.cc b/ui/gfx/geometry/insets_f_unittest.cc
new file mode 100644
index 0000000..3443aab
--- /dev/null
+++ b/ui/gfx/geometry/insets_f_unittest.cc
@@ -0,0 +1,238 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/insets_f.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/outsets_f.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/vector2d.h"
+
+namespace gfx {
+
+TEST(InsetsFTest, Default) {
+ InsetsF insets;
+ EXPECT_EQ(0, insets.top());
+ EXPECT_EQ(0, insets.left());
+ EXPECT_EQ(0, insets.bottom());
+ EXPECT_EQ(0, insets.right());
+}
+
+TEST(InsetsFTest, TLBR) {
+ InsetsF insets = InsetsF::TLBR(1.25f, 2.5f, 3.75f, 4.875f);
+ EXPECT_EQ(1.25f, insets.top());
+ EXPECT_EQ(2.5f, insets.left());
+ EXPECT_EQ(3.75f, insets.bottom());
+ EXPECT_EQ(4.875f, insets.right());
+}
+
+TEST(InsetsFTest, VH) {
+ InsetsF insets = InsetsF::VH(1.25f, 2.5f);
+ EXPECT_EQ(1.25f, insets.top());
+ EXPECT_EQ(2.5f, insets.left());
+ EXPECT_EQ(1.25f, insets.bottom());
+ EXPECT_EQ(2.5f, insets.right());
+}
+
+TEST(InsetsFTest, SetTop) {
+ InsetsF insets = InsetsF(1.5f);
+ insets.set_top(2.75f);
+ EXPECT_EQ(2.75f, insets.top());
+ EXPECT_EQ(1.5f, insets.left());
+ EXPECT_EQ(1.5f, insets.bottom());
+ EXPECT_EQ(1.5f, insets.right());
+ EXPECT_EQ(insets, InsetsF(1.5f).set_top(2.75f));
+}
+
+TEST(InsetsFTest, SetBottom) {
+ InsetsF insets(1.5f);
+ insets.set_bottom(2.75f);
+ EXPECT_EQ(1.5f, insets.top());
+ EXPECT_EQ(1.5f, insets.left());
+ EXPECT_EQ(2.75f, insets.bottom());
+ EXPECT_EQ(1.5f, insets.right());
+ EXPECT_EQ(insets, InsetsF(1.5f).set_bottom(2.75f));
+}
+
+TEST(InsetsFTest, SetLeft) {
+ InsetsF insets(1.5f);
+ insets.set_left(2.75f);
+ EXPECT_EQ(1.5f, insets.top());
+ EXPECT_EQ(2.75f, insets.left());
+ EXPECT_EQ(1.5f, insets.bottom());
+ EXPECT_EQ(1.5f, insets.right());
+ EXPECT_EQ(insets, InsetsF(1.5f).set_left(2.75f));
+}
+
+TEST(InsetsFTest, SetRight) {
+ InsetsF insets(1.5f);
+ insets.set_right(2.75f);
+ EXPECT_EQ(1.5f, insets.top());
+ EXPECT_EQ(1.5f, insets.left());
+ EXPECT_EQ(1.5f, insets.bottom());
+ EXPECT_EQ(2.75f, insets.right());
+ EXPECT_EQ(insets, InsetsF(1.5f).set_right(2.75f));
+}
+
+TEST(InsetsFTest, WidthHeightAndIsEmpty) {
+ InsetsF insets;
+ EXPECT_EQ(0, insets.width());
+ EXPECT_EQ(0, insets.height());
+ EXPECT_TRUE(insets.IsEmpty());
+
+ insets.set_left(3.5f).set_right(4.25f);
+ EXPECT_EQ(7.75f, insets.width());
+ EXPECT_EQ(0, insets.height());
+ EXPECT_FALSE(insets.IsEmpty());
+
+ insets.set_left(0).set_right(0).set_top(1.5f).set_bottom(2.75f);
+ EXPECT_EQ(0, insets.width());
+ EXPECT_EQ(4.25f, insets.height());
+ EXPECT_FALSE(insets.IsEmpty());
+
+ insets.set_left(4.25f).set_right(5);
+ EXPECT_EQ(9.25f, insets.width());
+ EXPECT_EQ(4.25f, insets.height());
+ EXPECT_FALSE(insets.IsEmpty());
+}
+
+TEST(InsetsFTest, Operators) {
+ InsetsF insets =
+ InsetsF().set_left(2.5f).set_right(4.1f).set_top(1.f).set_bottom(3.3f);
+ insets +=
+ InsetsF().set_left(6.7f).set_right(8.5f).set_top(5.8f).set_bottom(7.6f);
+ EXPECT_FLOAT_EQ(6.8f, insets.top());
+ EXPECT_FLOAT_EQ(9.2f, insets.left());
+ EXPECT_FLOAT_EQ(10.9f, insets.bottom());
+ EXPECT_FLOAT_EQ(12.6f, insets.right());
+
+ insets -=
+ InsetsF().set_left(0).set_right(2.2f).set_top(-1.f).set_bottom(1.1f);
+ EXPECT_FLOAT_EQ(7.8f, insets.top());
+ EXPECT_FLOAT_EQ(9.2f, insets.left());
+ EXPECT_FLOAT_EQ(9.8f, insets.bottom());
+ EXPECT_FLOAT_EQ(10.4f, insets.right());
+
+ insets =
+ InsetsF().set_left(10.1f).set_right(10.001f).set_top(10).set_bottom(
+ 10.01f) +
+ InsetsF().set_left(5.f).set_right(-20.2f).set_top(5.5f).set_bottom(0);
+ EXPECT_FLOAT_EQ(15.5f, insets.top());
+ EXPECT_FLOAT_EQ(15.1f, insets.left());
+ EXPECT_FLOAT_EQ(10.01f, insets.bottom());
+ EXPECT_FLOAT_EQ(-10.199f, insets.right());
+
+ insets =
+ InsetsF().set_left(10.1f).set_right(10.001f).set_top(10).set_bottom(
+ 10.01f) -
+ InsetsF().set_left(5.f).set_right(-20.2f).set_top(5.5f).set_bottom(0);
+ EXPECT_FLOAT_EQ(4.5f, insets.top());
+ EXPECT_FLOAT_EQ(5.1f, insets.left());
+ EXPECT_FLOAT_EQ(10.01f, insets.bottom());
+ EXPECT_FLOAT_EQ(30.201f, insets.right());
+}
+
+TEST(InsetsFTest, Equality) {
+ InsetsF insets1 =
+ InsetsF().set_left(2.2f).set_right(4.4f).set_top(1.1f).set_bottom(3.3f);
+ InsetsF insets2;
+ // Test operator== and operator!=.
+ EXPECT_FALSE(insets1 == insets2);
+ EXPECT_TRUE(insets1 != insets2);
+
+ insets2.set_left(2.2f).set_right(4.4f).set_top(1.1f).set_bottom(3.3f);
+ EXPECT_TRUE(insets1 == insets2);
+ EXPECT_FALSE(insets1 != insets2);
+}
+
+TEST(InsetsFTest, ToString) {
+ InsetsF insets =
+ InsetsF().set_left(2.2).set_right(4.4).set_top(1.1).set_bottom(3.3);
+ EXPECT_EQ("x:2.2,4.4 y:1.1,3.3", insets.ToString());
+}
+
+TEST(InsetsFTest, Scale) {
+ InsetsF in = InsetsF().set_left(5).set_right(1).set_top(7).set_bottom(3);
+ InsetsF testf = ScaleInsets(in, 2.5f, 3.5f);
+ EXPECT_EQ(InsetsF().set_left(12.5f).set_right(2.5f).set_top(24.5f).set_bottom(
+ 10.5f),
+ testf);
+ testf = ScaleInsets(in, 2.5f);
+ EXPECT_EQ(
+ InsetsF().set_left(12.5f).set_right(2.5f).set_top(17.5f).set_bottom(7.5f),
+ testf);
+
+ in.Scale(2.5f, 3.5f);
+ EXPECT_EQ(InsetsF().set_left(12.5f).set_right(2.5f).set_top(24.5f).set_bottom(
+ 10.5f),
+ in);
+ in.Scale(-2.5f);
+ EXPECT_EQ(
+ InsetsF().set_left(-31.25f).set_right(-6.25f).set_top(-61.25f).set_bottom(
+ -26.25f),
+ in);
+}
+
+TEST(InsetsFTest, ScaleNegative) {
+ InsetsF in = InsetsF().set_left(-5).set_right(-1).set_top(-7).set_bottom(-3);
+
+ InsetsF testf = ScaleInsets(in, 2.5f, 3.5f);
+ EXPECT_EQ(
+ InsetsF().set_left(-12.5f).set_right(-2.5f).set_top(-24.5f).set_bottom(
+ -10.5f),
+ testf);
+ testf = ScaleInsets(in, 2.5f);
+ EXPECT_EQ(
+ InsetsF().set_left(-12.5f).set_right(-2.5f).set_top(-17.5f).set_bottom(
+ -7.5f),
+ testf);
+
+ in.Scale(2.5f, 3.5f);
+ EXPECT_EQ(
+ InsetsF().set_left(-12.5f).set_right(-2.5f).set_top(-24.5f).set_bottom(
+ -10.5f),
+ in);
+ in.Scale(-2.5f);
+ EXPECT_EQ(
+ InsetsF().set_left(31.25f).set_right(6.25f).set_top(61.25f).set_bottom(
+ 26.25f),
+ in);
+}
+
+TEST(InsetsFTest, SetToMax) {
+ InsetsF insets;
+ insets.SetToMax(
+ InsetsF().set_left(2.5f).set_right(4.5f).set_top(-1.25f).set_bottom(
+ -2.5f));
+ EXPECT_EQ(InsetsF().set_left(2.5f).set_right(4.5f), insets);
+ insets.SetToMax(InsetsF());
+ EXPECT_EQ(InsetsF().set_left(2.5f).set_right(4.5f), insets);
+ insets.SetToMax(InsetsF().set_top(1.25f).set_bottom(3.75f));
+ EXPECT_EQ(
+ InsetsF().set_left(2.5f).set_right(4.5f).set_top(1.25f).set_bottom(3.75f),
+ insets);
+ insets.SetToMax(
+ InsetsF().set_left(30).set_right(50).set_top(20).set_bottom(40));
+ EXPECT_EQ(InsetsF().set_left(30).set_right(50).set_top(20).set_bottom(40),
+ insets);
+
+ InsetsF insets1 =
+ InsetsF().set_left(-2).set_right(-4).set_top(-1).set_bottom(-3);
+ insets1.SetToMax(InsetsF());
+ EXPECT_EQ(InsetsF(), insets1);
+}
+
+TEST(InsetsFTest, ConversionFromToOutsetsF) {
+ InsetsF insets =
+ InsetsF().set_left(2.5f).set_right(4.5f).set_top(-1.25f).set_bottom(
+ -2.5f);
+ EXPECT_EQ(
+ OutsetsF().set_left(-2.5f).set_right(-4.5f).set_top(1.25f).set_bottom(
+ 2.5f),
+ insets.ToOutsets());
+ EXPECT_EQ(insets, insets.ToOutsets().ToInsets());
+}
+
+} // namespace gfx
diff --git a/ui/gfx/geometry/insets_outsets_base.h b/ui/gfx/geometry/insets_outsets_base.h
new file mode 100644
index 0000000..d454379
--- /dev/null
+++ b/ui/gfx/geometry/insets_outsets_base.h
@@ -0,0 +1,163 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_INSETS_OUTSETS_BASE_H_
+#define UI_GFX_GEOMETRY_INSETS_OUTSETS_BASE_H_
+
+#include <string>
+
+#include "base/numerics/clamped_math.h"
+#include "base/strings/stringprintf.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace gfx {
+
+// The common base template class for Insets and Outsets.
+// Represents the widths of the four borders or margins of an unspecified
+// rectangle. It stores the thickness of the top, left, bottom and right
+// edges, without storing the actual size and position of the rectangle itself.
+template <typename T>
+class InsetsOutsetsBase {
+ public:
+ constexpr InsetsOutsetsBase() = default;
+ constexpr explicit InsetsOutsetsBase(int all)
+ : top_(all),
+ left_(all),
+ bottom_(ClampBottomOrRight(all, all)),
+ right_(ClampBottomOrRight(all, all)) {}
+
+ constexpr int top() const { return top_; }
+ constexpr int left() const { return left_; }
+ constexpr int bottom() const { return bottom_; }
+ constexpr int right() const { return right_; }
+
+ // Returns the total width taken up by the insets/outsets, which is the sum
+ // of the left and right insets/outsets.
+ constexpr int width() const { return left_ + right_; }
+
+ // Returns the total height taken up by the insets/outsets, which is the sum
+ // of the top and bottom insets/outsets.
+ constexpr int height() const { return top_ + bottom_; }
+
+ // Returns the sum of the left and right insets/outsets as the width,
+ // the sum of the top and bottom insets/outsets as the height.
+ constexpr Size size() const { return Size(width(), height()); }
+
+ // Returns true if the insets/outsets are empty.
+ bool IsEmpty() const { return width() == 0 && height() == 0; }
+
+ // These setters can be used together with the default constructor and the
+ // single-parameter constructor to construct Insets instances, for example:
+ // // T, L, B, R
+ // Insets a = Insets().set_top(2); // 2, 0, 0, 0
+ // Insets b = Insets().set_left(2).set_bottom(3); // 0, 2, 3, 0
+ // Insets c = Insets().set_left_right(1, 2).set_top_bottom(3, 4);
+ // // 3, 1, 4, 2
+ // Insets d = Insets(1).set_top(5); // 5, 1, 1, 1
+ constexpr T& set_top(int top) {
+ top_ = top;
+ bottom_ = ClampBottomOrRight(top_, bottom_);
+ return *static_cast<T*>(this);
+ }
+ constexpr T& set_left(int left) {
+ left_ = left;
+ right_ = ClampBottomOrRight(left_, right_);
+ return *static_cast<T*>(this);
+ }
+ constexpr T& set_bottom(int bottom) {
+ bottom_ = ClampBottomOrRight(top_, bottom);
+ return *static_cast<T*>(this);
+ }
+ constexpr T& set_right(int right) {
+ right_ = ClampBottomOrRight(left_, right);
+ return *static_cast<T*>(this);
+ }
+ // These are preferred to the above setters when setting a pair of edges
+ // because these have less clamping and better performance.
+ constexpr T& set_left_right(int left, int right) {
+ left_ = left;
+ right_ = ClampBottomOrRight(left_, right);
+ return *static_cast<T*>(this);
+ }
+ constexpr T& set_top_bottom(int top, int bottom) {
+ top_ = top;
+ bottom_ = ClampBottomOrRight(top_, bottom);
+ return *static_cast<T*>(this);
+ }
+
+ // In addition to the above, we can also use the following methods to
+ // construct Insets/Outsets.
+ // TLBR() is for Chomium UI code. We should not use it in blink code because
+ // the order of parameters is different from the normal orders used in blink.
+ // Blink code can use the above setters and VH().
+ static constexpr T TLBR(int top, int left, int bottom, int right) {
+ return T().set_top_bottom(top, bottom).set_left_right(left, right);
+ }
+ static constexpr T VH(int vertical, int horizontal) {
+ return TLBR(vertical, horizontal, vertical, horizontal);
+ }
+
+ // Sets each side to the maximum of the side and the corresponding side of
+ // |other|.
+ void SetToMax(const T& other) {
+ top_ = std::max(top_, other.top_);
+ left_ = std::max(left_, other.left_);
+ bottom_ = std::max(bottom_, other.bottom_);
+ right_ = std::max(right_, other.right_);
+ }
+
+ bool operator==(const InsetsOutsetsBase<T>& other) const {
+ return top_ == other.top_ && left_ == other.left_ &&
+ bottom_ == other.bottom_ && right_ == other.right_;
+ }
+
+ bool operator!=(const InsetsOutsetsBase<T>& other) const {
+ return !(*this == other);
+ }
+
+ void operator+=(const T& other) {
+ top_ = base::ClampAdd(top_, other.top_);
+ left_ = base::ClampAdd(left_, other.left_);
+ bottom_ = ClampBottomOrRight(top_, base::ClampAdd(bottom_, other.bottom_));
+ right_ = ClampBottomOrRight(left_, base::ClampAdd(right_, other.right_));
+ }
+
+ void operator-=(const T& other) {
+ top_ = base::ClampSub(top_, other.top_);
+ left_ = base::ClampSub(left_, other.left_);
+ bottom_ = ClampBottomOrRight(top_, base::ClampSub(bottom_, other.bottom_));
+ right_ = ClampBottomOrRight(left_, base::ClampSub(right_, other.right_));
+ }
+
+ T operator-() const {
+ return T()
+ .set_left_right(-base::MakeClampedNum(left_),
+ -base::MakeClampedNum(right_))
+ .set_top_bottom(-base::MakeClampedNum(top_),
+ -base::MakeClampedNum(bottom_));
+ }
+
+ // Returns a string representation of the insets/outsets.
+ std::string ToString() const {
+ return base::StringPrintf("x:%d,%d y:%d,%d", left_, right_, top_, bottom_);
+ }
+
+ private:
+ // Clamp the bottom/right to avoid integer over/underflow in width() and
+ // height(). This returns the clamped bottom/right given a |top_or_left| and
+ // a |bottom_or_right|.
+ static constexpr int ClampBottomOrRight(int top_or_left,
+ int bottom_or_right) {
+ return base::ClampAdd(top_or_left, bottom_or_right) - top_or_left;
+ }
+
+ int top_ = 0;
+ int left_ = 0;
+ int bottom_ = 0;
+ int right_ = 0;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_INSETS_OUTSETS_BASE_H_
diff --git a/ui/gfx/geometry/insets_outsets_f_base.h b/ui/gfx/geometry/insets_outsets_f_base.h
new file mode 100644
index 0000000..c052e7d
--- /dev/null
+++ b/ui/gfx/geometry/insets_outsets_f_base.h
@@ -0,0 +1,135 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_INSETS_OUTSETS_F_BASE_H_
+#define UI_GFX_GEOMETRY_INSETS_OUTSETS_F_BASE_H_
+
+#include <string>
+
+#include "base/strings/stringprintf.h"
+
+namespace gfx {
+
+// This is the base template class of InsetsF and OutsetsF.
+template <typename T>
+class InsetsOutsetsFBase {
+ public:
+ constexpr InsetsOutsetsFBase() = default;
+ constexpr explicit InsetsOutsetsFBase(float all)
+ : top_(all), left_(all), bottom_(all), right_(all) {}
+
+ constexpr float top() const { return top_; }
+ constexpr float left() const { return left_; }
+ constexpr float bottom() const { return bottom_; }
+ constexpr float right() const { return right_; }
+
+ // Returns the total width taken up by the insets/outsets, which is the
+ // sum of the left and right insets/outsets.
+ constexpr float width() const { return left_ + right_; }
+
+ // Returns the total height taken up by the insets/outsets, which is the
+ // sum of the top and bottom insets/outsets.
+ constexpr float height() const { return top_ + bottom_; }
+
+ // Returns true if the insets/outsets are empty.
+ bool IsEmpty() const { return width() == 0.f && height() == 0.f; }
+
+ // These setters can be used together with the default constructor and the
+ // single-parameter constructor to construct InsetsF instances, for example:
+ // // T, L, B, R
+ // InsetsF a = InsetsF().set_top(2); // 2, 0, 0, 0
+ // InsetsF b = InsetsF().set_left(2).set_bottom(3); // 0, 2, 3, 0
+ // InsetsF c = InsetsF(1).set_top(5); // 5, 1, 1, 1
+ constexpr T& set_top(float top) {
+ top_ = top;
+ return *static_cast<T*>(this);
+ }
+ constexpr T& set_left(float left) {
+ left_ = left;
+ return *static_cast<T*>(this);
+ }
+ constexpr T& set_bottom(float bottom) {
+ bottom_ = bottom;
+ return *static_cast<T*>(this);
+ }
+ constexpr T& set_right(float right) {
+ right_ = right;
+ return *static_cast<T*>(this);
+ }
+
+ // In addition to the above, we can also use the following methods to
+ // construct InsetsF/OutsetsF.
+ // TLBR() is for Chomium UI code. We should not use it in blink code because
+ // the order of parameters is different from the normal orders used in blink.
+ // Blink code can use the above setters and VH().
+ static constexpr inline T TLBR(float top,
+ float left,
+ float bottom,
+ float right) {
+ return T().set_top(top).set_left(left).set_bottom(bottom).set_right(right);
+ }
+ static constexpr inline T VH(float vertical, float horizontal) {
+ return TLBR(vertical, horizontal, vertical, horizontal);
+ }
+
+ // Sets each side to the maximum of the side and the corresponding side of
+ // |other|.
+ void SetToMax(const T& other) {
+ top_ = std::max(top_, other.top_);
+ left_ = std::max(left_, other.left_);
+ bottom_ = std::max(bottom_, other.bottom_);
+ right_ = std::max(right_, other.right_);
+ }
+
+ void Scale(float x_scale, float y_scale) {
+ top_ *= y_scale;
+ left_ *= x_scale;
+ bottom_ *= y_scale;
+ right_ *= x_scale;
+ }
+ void Scale(float scale) { Scale(scale, scale); }
+
+ bool operator==(const InsetsOutsetsFBase<T>& other) const {
+ return top_ == other.top_ && left_ == other.left_ &&
+ bottom_ == other.bottom_ && right_ == other.right_;
+ }
+
+ bool operator!=(const InsetsOutsetsFBase<T>& other) const {
+ return !(*this == other);
+ }
+
+ void operator+=(const T& other) {
+ top_ += other.top_;
+ left_ += other.left_;
+ bottom_ += other.bottom_;
+ right_ += other.right_;
+ }
+
+ void operator-=(const T& other) {
+ top_ -= other.top_;
+ left_ -= other.left_;
+ bottom_ -= other.bottom_;
+ right_ -= other.right_;
+ }
+
+ T operator-() const {
+ return T().set_left(-left_).set_right(-right_).set_top(-top_).set_bottom(
+ -bottom_);
+ }
+
+ // Returns a string representation of the insets/outsets.
+ std::string ToString() const {
+ return base::StringPrintf("x:%g,%g y:%g,%g", left_, right_, top_, bottom_);
+ }
+
+ private:
+ float top_ = 0.f;
+ float left_ = 0.f;
+ float bottom_ = 0.f;
+ float right_ = 0.f;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_INSETS_OUTSETS_F_BASE_H_
diff --git a/ui/gfx/geometry/insets_unittest.cc b/ui/gfx/geometry/insets_unittest.cc
index 83ef910..0972ae5 100644
--- a/ui/gfx/geometry/insets_unittest.cc
+++ b/ui/gfx/geometry/insets_unittest.cc
@@ -1,267 +1,287 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright 2009 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/insets.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/insets_f.h"
+#include "ui/gfx/geometry/outsets.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/vector2d.h"
-TEST(InsetsTest, InsetsDefault) {
- gfx::Insets insets;
+namespace gfx {
+
+TEST(InsetsTest, Default) {
+ Insets insets;
EXPECT_EQ(0, insets.top());
EXPECT_EQ(0, insets.left());
EXPECT_EQ(0, insets.bottom());
EXPECT_EQ(0, insets.right());
- EXPECT_EQ(0, insets.width());
- EXPECT_EQ(0, insets.height());
- EXPECT_TRUE(insets.IsEmpty());
}
-TEST(InsetsTest, Insets) {
- gfx::Insets insets(1, 2, 3, 4);
+TEST(InsetsTest, TLBR) {
+ Insets insets = Insets::TLBR(1, 2, 3, 4);
EXPECT_EQ(1, insets.top());
EXPECT_EQ(2, insets.left());
EXPECT_EQ(3, insets.bottom());
EXPECT_EQ(4, insets.right());
- EXPECT_EQ(6, insets.width()); // Left + right.
- EXPECT_EQ(4, insets.height()); // Top + bottom.
- EXPECT_FALSE(insets.IsEmpty());
+}
+
+TEST(InsetsTest, VH) {
+ Insets insets = Insets::VH(1, 2);
+ EXPECT_EQ(1, insets.top());
+ EXPECT_EQ(2, insets.left());
+ EXPECT_EQ(1, insets.bottom());
+ EXPECT_EQ(2, insets.right());
+}
+
+TEST(InsetsTest, SetLeftRight) {
+ Insets insets(1);
+ insets.set_left_right(3, 4);
+ EXPECT_EQ(1, insets.top());
+ EXPECT_EQ(3, insets.left());
+ EXPECT_EQ(1, insets.bottom());
+ EXPECT_EQ(4, insets.right());
+
+ EXPECT_EQ(insets, Insets(1).set_left_right(3, 4));
+}
+
+TEST(InsetsTest, SetTopBottom) {
+ Insets insets(1);
+ insets.set_top_bottom(3, 4);
+ EXPECT_EQ(3, insets.top());
+ EXPECT_EQ(1, insets.left());
+ EXPECT_EQ(4, insets.bottom());
+ EXPECT_EQ(1, insets.right());
+
+ EXPECT_EQ(insets, Insets(1).set_top_bottom(3, 4));
}
TEST(InsetsTest, SetTop) {
- gfx::Insets insets(1);
+ Insets insets(1);
insets.set_top(2);
- EXPECT_EQ(gfx::Insets(2, 1, 1, 1), insets);
+ EXPECT_EQ(2, insets.top());
+ EXPECT_EQ(1, insets.left());
+ EXPECT_EQ(1, insets.bottom());
+ EXPECT_EQ(1, insets.right());
+ EXPECT_EQ(insets, Insets(1).set_top(2));
}
TEST(InsetsTest, SetBottom) {
- gfx::Insets insets(1);
+ Insets insets(1);
insets.set_bottom(2);
- EXPECT_EQ(gfx::Insets(1, 1, 2, 1), insets);
+ EXPECT_EQ(1, insets.top());
+ EXPECT_EQ(1, insets.left());
+ EXPECT_EQ(2, insets.bottom());
+ EXPECT_EQ(1, insets.right());
+ EXPECT_EQ(insets, Insets(1).set_bottom(2));
}
TEST(InsetsTest, SetLeft) {
- gfx::Insets insets(1);
+ Insets insets(1);
insets.set_left(2);
- EXPECT_EQ(gfx::Insets(1, 2, 1, 1), insets);
+ EXPECT_EQ(1, insets.top());
+ EXPECT_EQ(2, insets.left());
+ EXPECT_EQ(1, insets.bottom());
+ EXPECT_EQ(1, insets.right());
+ EXPECT_EQ(insets, Insets(1).set_left(2));
}
TEST(InsetsTest, SetRight) {
- gfx::Insets insets(1);
+ Insets insets(1);
insets.set_right(2);
- EXPECT_EQ(gfx::Insets(1, 1, 1, 2), insets);
+ EXPECT_EQ(1, insets.top());
+ EXPECT_EQ(1, insets.left());
+ EXPECT_EQ(1, insets.bottom());
+ EXPECT_EQ(2, insets.right());
+ EXPECT_EQ(insets, Insets(1).set_right(2));
}
-TEST(InsetsTest, Set) {
- gfx::Insets insets;
- insets.Set(1, 2, 3, 4);
- EXPECT_EQ(1, insets.top());
- EXPECT_EQ(2, insets.left());
- EXPECT_EQ(3, insets.bottom());
- EXPECT_EQ(4, insets.right());
+TEST(InsetsTest, WidthHeightAndIsEmpty) {
+ Insets insets;
+ EXPECT_EQ(0, insets.width());
+ EXPECT_EQ(0, insets.height());
+ EXPECT_TRUE(insets.IsEmpty());
+
+ insets.set_left_right(3, 4);
+ EXPECT_EQ(7, insets.width());
+ EXPECT_EQ(0, insets.height());
+ EXPECT_FALSE(insets.IsEmpty());
+
+ insets.set_left_right(0, 0);
+ insets.set_top_bottom(1, 2);
+ EXPECT_EQ(0, insets.width());
+ EXPECT_EQ(3, insets.height());
+ EXPECT_FALSE(insets.IsEmpty());
+
+ insets.set_left_right(4, 5);
+ EXPECT_EQ(9, insets.width());
+ EXPECT_EQ(3, insets.height());
+ EXPECT_FALSE(insets.IsEmpty());
}
TEST(InsetsTest, Operators) {
- gfx::Insets insets;
- insets.Set(1, 2, 3, 4);
- insets += gfx::Insets(5, 6, 7, 8);
+ Insets insets = Insets().set_left_right(2, 4).set_top_bottom(1, 3);
+ insets += Insets().set_left_right(6, 8).set_top_bottom(5, 7);
EXPECT_EQ(6, insets.top());
EXPECT_EQ(8, insets.left());
EXPECT_EQ(10, insets.bottom());
EXPECT_EQ(12, insets.right());
- insets -= gfx::Insets(-1, 0, 1, 2);
+ insets -= Insets().set_left_right(0, 2).set_top_bottom(-1, 1);
EXPECT_EQ(7, insets.top());
EXPECT_EQ(8, insets.left());
EXPECT_EQ(9, insets.bottom());
EXPECT_EQ(10, insets.right());
- insets = gfx::Insets(10, 10, 10, 10) + gfx::Insets(5, 5, 0, -20);
- EXPECT_EQ(15, insets.top());
+ insets = Insets(10) + Insets().set_left_right(5, -20).set_top_bottom(10, 0);
+ EXPECT_EQ(20, insets.top());
EXPECT_EQ(15, insets.left());
EXPECT_EQ(10, insets.bottom());
EXPECT_EQ(-10, insets.right());
- insets = gfx::Insets(10, 10, 10, 10) - gfx::Insets(5, 5, 0, -20);
- EXPECT_EQ(5, insets.top());
+ insets = Insets(10) - Insets().set_left_right(5, -20).set_top_bottom(10, 0);
+ EXPECT_EQ(0, insets.top());
EXPECT_EQ(5, insets.left());
EXPECT_EQ(10, insets.bottom());
EXPECT_EQ(30, insets.right());
}
-TEST(InsetsFTest, Operators) {
- gfx::InsetsF insets;
- insets.Set(1.f, 2.5f, 3.3f, 4.1f);
- insets += gfx::InsetsF(5.8f, 6.7f, 7.6f, 8.5f);
- EXPECT_FLOAT_EQ(6.8f, insets.top());
- EXPECT_FLOAT_EQ(9.2f, insets.left());
- EXPECT_FLOAT_EQ(10.9f, insets.bottom());
- EXPECT_FLOAT_EQ(12.6f, insets.right());
-
- insets -= gfx::InsetsF(-1.f, 0, 1.1f, 2.2f);
- EXPECT_FLOAT_EQ(7.8f, insets.top());
- EXPECT_FLOAT_EQ(9.2f, insets.left());
- EXPECT_FLOAT_EQ(9.8f, insets.bottom());
- EXPECT_FLOAT_EQ(10.4f, insets.right());
-
- insets = gfx::InsetsF(10, 10.1f, 10.01f, 10.001f) +
- gfx::InsetsF(5.5f, 5.f, 0, -20.2f);
- EXPECT_FLOAT_EQ(15.5f, insets.top());
- EXPECT_FLOAT_EQ(15.1f, insets.left());
- EXPECT_FLOAT_EQ(10.01f, insets.bottom());
- EXPECT_FLOAT_EQ(-10.199f, insets.right());
-
- insets = gfx::InsetsF(10, 10.1f, 10.01f, 10.001f) -
- gfx::InsetsF(5.5f, 5.f, 0, -20.2f);
- EXPECT_FLOAT_EQ(4.5f, insets.top());
- EXPECT_FLOAT_EQ(5.1f, insets.left());
- EXPECT_FLOAT_EQ(10.01f, insets.bottom());
- EXPECT_FLOAT_EQ(30.201f, insets.right());
-}
-
TEST(InsetsTest, Equality) {
- gfx::Insets insets1;
- insets1.Set(1, 2, 3, 4);
- gfx::Insets insets2;
+ Insets insets1 = Insets().set_left_right(2, 4).set_top_bottom(1, 3);
+ Insets insets2;
// Test operator== and operator!=.
EXPECT_FALSE(insets1 == insets2);
EXPECT_TRUE(insets1 != insets2);
- insets2.Set(1, 2, 3, 4);
+ insets2.set_left_right(2, 4).set_top_bottom(1, 3);
EXPECT_TRUE(insets1 == insets2);
EXPECT_FALSE(insets1 != insets2);
}
TEST(InsetsTest, ToString) {
- gfx::Insets insets(1, 2, 3, 4);
- EXPECT_EQ("1,2,3,4", insets.ToString());
+ Insets insets = Insets().set_left_right(2, 4).set_top_bottom(1, 3);
+ EXPECT_EQ("x:2,4 y:1,3", insets.ToString());
}
TEST(InsetsTest, Offset) {
- const gfx::Insets insets(1, 2, 3, 4);
- const gfx::Rect rect(5, 6, 7, 8);
- const gfx::Vector2d vector(9, 10);
+ const Insets insets = Insets().set_left_right(2, 4).set_top_bottom(1, 3);
+ const Rect rect(5, 6, 7, 8);
+ const Vector2d vector(9, 10);
// Whether you inset then offset the rect, offset then inset the rect, or
// offset the insets then apply to the rect, the outcome should be the same.
- gfx::Rect inset_first = rect;
+ Rect inset_first = rect;
inset_first.Inset(insets);
inset_first.Offset(vector);
- gfx::Rect offset_first = rect;
+ Rect offset_first = rect;
offset_first.Offset(vector);
offset_first.Inset(insets);
- gfx::Rect inset_by_offset = rect;
- inset_by_offset.Inset(insets.Offset(vector));
+ Insets insets_with_offset = insets;
+ insets_with_offset.Offset(vector);
+ EXPECT_EQ(gfx::Insets().set_left_right(11, -5).set_top_bottom(11, -7),
+ insets_with_offset);
+ EXPECT_EQ(insets_with_offset, insets + vector);
+
+ Rect inset_by_offset = rect;
+ inset_by_offset.Inset(insets_with_offset);
EXPECT_EQ(inset_first, offset_first);
EXPECT_EQ(inset_by_offset, inset_first);
}
TEST(InsetsTest, Scale) {
- gfx::Insets in(7, 5);
+ Insets in = Insets().set_left_right(5, 1).set_top_bottom(7, 3);
- gfx::InsetsF testf = gfx::ScaleInsets(in, 2.5f, 3.5f);
- EXPECT_EQ(gfx::InsetsF(24.5f, 12.5f), testf);
- testf = gfx::ScaleInsets(in, 2.5f);
- EXPECT_EQ(gfx::InsetsF(17.5f, 12.5f), testf);
+ Insets test = ScaleToFlooredInsets(in, 2.5f, 3.5f);
+ EXPECT_EQ(Insets().set_left_right(12, 2).set_top_bottom(24, 10), test);
+ test = ScaleToFlooredInsets(in, 2.5f);
+ EXPECT_EQ(Insets().set_left_right(12, 2).set_top_bottom(17, 7), test);
- gfx::Insets test = gfx::ScaleToFlooredInsets(in, 2.5f, 3.5f);
- EXPECT_EQ(gfx::Insets(24, 12), test);
- test = gfx::ScaleToFlooredInsets(in, 2.5f);
- EXPECT_EQ(gfx::Insets(17, 12), test);
+ test = ScaleToCeiledInsets(in, 2.5f, 3.5f);
+ EXPECT_EQ(Insets().set_left_right(13, 3).set_top_bottom(25, 11), test);
+ test = ScaleToCeiledInsets(in, 2.5f);
+ EXPECT_EQ(Insets().set_left_right(13, 3).set_top_bottom(18, 8), test);
- test = gfx::ScaleToCeiledInsets(in, 2.5f, 3.5f);
- EXPECT_EQ(gfx::Insets(25, 13), test);
- test = gfx::ScaleToCeiledInsets(in, 2.5f);
- EXPECT_EQ(gfx::Insets(18, 13), test);
+ test = ScaleToRoundedInsets(in, 2.49f, 3.49f);
+ EXPECT_EQ(Insets().set_left_right(12, 2).set_top_bottom(24, 10), test);
+ test = ScaleToRoundedInsets(in, 2.49f);
+ EXPECT_EQ(Insets().set_left_right(12, 2).set_top_bottom(17, 7), test);
- test = gfx::ScaleToRoundedInsets(in, 2.49f, 3.49f);
- EXPECT_EQ(gfx::Insets(24, 12), test);
- test = gfx::ScaleToRoundedInsets(in, 2.49f);
- EXPECT_EQ(gfx::Insets(17, 12), test);
-
- test = gfx::ScaleToRoundedInsets(in, 2.5f, 3.5f);
- EXPECT_EQ(gfx::Insets(25, 13), test);
- test = gfx::ScaleToRoundedInsets(in, 2.5f);
- EXPECT_EQ(gfx::Insets(18, 13), test);
+ test = ScaleToRoundedInsets(in, 2.5f, 3.5f);
+ EXPECT_EQ(Insets().set_left_right(13, 3).set_top_bottom(25, 11), test);
+ test = ScaleToRoundedInsets(in, 2.5f);
+ EXPECT_EQ(Insets().set_left_right(13, 3).set_top_bottom(18, 8), test);
}
TEST(InsetsTest, ScaleNegative) {
- gfx::Insets in(-7, -5);
+ Insets in = Insets().set_left_right(-5, -1).set_top_bottom(-7, -3);
- gfx::InsetsF testf = gfx::ScaleInsets(in, 2.5f, 3.5f);
- EXPECT_EQ(gfx::InsetsF(-24.5f, -12.5f), testf);
- testf = gfx::ScaleInsets(in, 2.5f);
- EXPECT_EQ(gfx::InsetsF(-17.5f, -12.5f), testf);
+ Insets test = ScaleToFlooredInsets(in, 2.5f, 3.5f);
+ EXPECT_EQ(Insets().set_left_right(-13, -3).set_top_bottom(-25, -11), test);
+ test = ScaleToFlooredInsets(in, 2.5f);
+ EXPECT_EQ(Insets().set_left_right(-13, -3).set_top_bottom(-18, -8), test);
- gfx::Insets test = gfx::ScaleToFlooredInsets(in, 2.5f, 3.5f);
- EXPECT_EQ(gfx::Insets(-25, -13), test);
- test = gfx::ScaleToFlooredInsets(in, 2.5f);
- EXPECT_EQ(gfx::Insets(-18, -13), test);
+ test = ScaleToCeiledInsets(in, 2.5f, 3.5f);
+ EXPECT_EQ(Insets().set_left_right(-12, -2).set_top_bottom(-24, -10), test);
+ test = ScaleToCeiledInsets(in, 2.5f);
+ EXPECT_EQ(Insets().set_left_right(-12, -2).set_top_bottom(-17, -7), test);
- test = gfx::ScaleToCeiledInsets(in, 2.5f, 3.5f);
- EXPECT_EQ(gfx::Insets(-24, -12), test);
- test = gfx::ScaleToCeiledInsets(in, 2.5f);
- EXPECT_EQ(gfx::Insets(-17, -12), test);
+ test = ScaleToRoundedInsets(in, 2.49f, 3.49f);
+ EXPECT_EQ(Insets().set_left_right(-12, -2).set_top_bottom(-24, -10), test);
+ test = ScaleToRoundedInsets(in, 2.49f);
+ EXPECT_EQ(Insets().set_left_right(-12, -2).set_top_bottom(-17, -7), test);
- test = gfx::ScaleToRoundedInsets(in, 2.49f, 3.49f);
- EXPECT_EQ(gfx::Insets(-24, -12), test);
- test = gfx::ScaleToRoundedInsets(in, 2.49f);
- EXPECT_EQ(gfx::Insets(-17, -12), test);
-
- test = gfx::ScaleToRoundedInsets(in, 2.5f, 3.5f);
- EXPECT_EQ(gfx::Insets(-25, -13), test);
- test = gfx::ScaleToRoundedInsets(in, 2.5f);
- EXPECT_EQ(gfx::Insets(-18, -13), test);
+ test = ScaleToRoundedInsets(in, 2.5f, 3.5f);
+ EXPECT_EQ(Insets().set_left_right(-13, -3).set_top_bottom(-25, -11), test);
+ test = ScaleToRoundedInsets(in, 2.5f);
+ EXPECT_EQ(Insets().set_left_right(-13, -3).set_top_bottom(-18, -8), test);
}
TEST(InsetsTest, IntegerOverflow) {
constexpr int int_min = std::numeric_limits<int>::min();
constexpr int int_max = std::numeric_limits<int>::max();
- gfx::Insets width_height_test(int_max);
+ Insets width_height_test(int_max);
EXPECT_EQ(int_max, width_height_test.width());
EXPECT_EQ(int_max, width_height_test.height());
- gfx::Insets plus_test(int_max);
- plus_test += gfx::Insets(int_max);
- EXPECT_EQ(gfx::Insets(int_max), plus_test);
+ Insets plus_test(int_max);
+ plus_test += Insets(int_max);
+ EXPECT_EQ(Insets(int_max), plus_test);
- gfx::Insets negation_test = -gfx::Insets(int_min);
- EXPECT_EQ(gfx::Insets(int_max), negation_test);
+ Insets negation_test = -Insets(int_min);
+ EXPECT_EQ(Insets(int_max), negation_test);
- gfx::Insets scale_test(int_max);
- scale_test = gfx::ScaleToRoundedInsets(scale_test, 2.f);
- EXPECT_EQ(gfx::Insets(int_max), scale_test);
+ Insets scale_test(int_max);
+ scale_test = ScaleToRoundedInsets(scale_test, 2.f);
+ EXPECT_EQ(Insets(int_max), scale_test);
}
TEST(InsetsTest, IntegerUnderflow) {
constexpr int int_min = std::numeric_limits<int>::min();
constexpr int int_max = std::numeric_limits<int>::max();
- gfx::Insets width_height_test = gfx::Insets(int_min);
+ Insets width_height_test = Insets(int_min);
EXPECT_EQ(int_min, width_height_test.width());
EXPECT_EQ(int_min, width_height_test.height());
- gfx::Insets minus_test(int_min);
- minus_test -= gfx::Insets(int_max);
- EXPECT_EQ(gfx::Insets(int_min), minus_test);
+ Insets minus_test(int_min);
+ minus_test -= Insets(int_max);
+ EXPECT_EQ(Insets(int_min), minus_test);
- gfx::Insets scale_test = gfx::Insets(int_min);
- scale_test = gfx::ScaleToRoundedInsets(scale_test, 2.f);
- EXPECT_EQ(gfx::Insets(int_min), scale_test);
+ Insets scale_test = Insets(int_min);
+ scale_test = ScaleToRoundedInsets(scale_test, 2.f);
+ EXPECT_EQ(Insets(int_min), scale_test);
}
TEST(InsetsTest, IntegerOverflowSetVariants) {
constexpr int int_max = std::numeric_limits<int>::max();
- gfx::Insets set_test(20);
+ Insets set_test(20);
set_test.set_top(int_max);
EXPECT_EQ(int_max, set_test.top());
EXPECT_EQ(0, set_test.bottom());
@@ -270,7 +290,7 @@
EXPECT_EQ(int_max, set_test.left());
EXPECT_EQ(0, set_test.right());
- set_test = gfx::Insets(30);
+ set_test = Insets(30);
set_test.set_bottom(int_max);
EXPECT_EQ(int_max - 30, set_test.bottom());
EXPECT_EQ(30, set_test.top());
@@ -283,7 +303,7 @@
TEST(InsetsTest, IntegerUnderflowSetVariants) {
constexpr int int_min = std::numeric_limits<int>::min();
- gfx::Insets set_test(-20);
+ Insets set_test(-20);
set_test.set_top(int_min);
EXPECT_EQ(int_min, set_test.top());
EXPECT_EQ(0, set_test.bottom());
@@ -292,7 +312,7 @@
EXPECT_EQ(int_min, set_test.left());
EXPECT_EQ(0, set_test.right());
- set_test = gfx::Insets(-30);
+ set_test = Insets(-30);
set_test.set_bottom(int_min);
EXPECT_EQ(int_min + 30, set_test.bottom());
EXPECT_EQ(-30, set_test.top());
@@ -305,32 +325,63 @@
TEST(InsetsTest, IntegerOverflowSet) {
constexpr int int_max = std::numeric_limits<int>::max();
- gfx::Insets set_all_test;
- set_all_test.Set(10, 20, int_max, int_max);
- EXPECT_EQ(gfx::Insets(10, 20, int_max - 10, int_max - 20), set_all_test);
+ Insets set_all_test =
+ Insets().set_left_right(int_max, 20).set_top_bottom(10, int_max);
+ EXPECT_EQ(
+ Insets().set_left_right(int_max, 0).set_top_bottom(10, int_max - 10),
+ set_all_test);
}
TEST(InsetsTest, IntegerOverflowOffset) {
constexpr int int_max = std::numeric_limits<int>::max();
const gfx::Vector2d max_vector(int_max, int_max);
- gfx::Insets insets(1, 2, 3, 4);
- gfx::Insets offset_test = insets.Offset(max_vector);
- EXPECT_EQ(gfx::Insets(int_max, int_max, 3 - int_max, 4 - int_max),
- offset_test);
+ Insets insets = Insets().set_left_right(2, 4).set_top_bottom(1, 3);
+ insets.Offset(max_vector);
+ EXPECT_EQ(gfx::Insets()
+ .set_left_right(int_max, 4 - int_max)
+ .set_top_bottom(int_max, 3 - int_max),
+ insets);
}
TEST(InsetsTest, IntegerUnderflowOffset) {
constexpr int int_min = std::numeric_limits<int>::min();
- const gfx::Vector2d min_vector(int_min, int_min);
- gfx::Insets insets(-10);
- gfx::Insets offset_test = insets.Offset(min_vector);
- EXPECT_EQ(gfx::Insets(int_min, int_min, -10 - int_min, -10 - int_min),
- offset_test);
+ const Vector2d min_vector(int_min, int_min);
+ Insets insets(-10);
+ insets.Offset(min_vector);
+ EXPECT_EQ(gfx::Insets()
+ .set_left_right(int_min, -10 - int_min)
+ .set_top_bottom(int_min, -10 - int_min),
+ insets);
}
TEST(InsetsTest, Size) {
- gfx::Insets insets(1, 2, 3, 4);
- EXPECT_EQ(gfx::Size(6, 4), insets.size());
+ Insets insets = Insets().set_left_right(2, 4).set_top_bottom(1, 3);
+ EXPECT_EQ(Size(6, 4), insets.size());
}
+
+TEST(InsetsTest, SetToMax) {
+ Insets insets;
+ insets.SetToMax(Insets().set_left_right(2, 4).set_top_bottom(-1, -3));
+ EXPECT_EQ(Insets().set_left_right(2, 4), insets);
+ insets.SetToMax(Insets());
+ EXPECT_EQ(Insets().set_left_right(2, 4), insets);
+ insets.SetToMax(Insets().set_top_bottom(1, 3));
+ EXPECT_EQ(Insets().set_left_right(2, 4).set_top_bottom(1, 3), insets);
+ insets.SetToMax(Insets().set_left_right(30, 50).set_top_bottom(20, 40));
+ EXPECT_EQ(Insets().set_left_right(30, 50).set_top_bottom(20, 40), insets);
+
+ Insets insets1 = Insets().set_left_right(-2, -4).set_top_bottom(-2, -4);
+ insets1.SetToMax(Insets());
+ EXPECT_EQ(Insets(), insets1);
+}
+
+TEST(InsetsTest, ConversionFromToOutsets) {
+ Insets insets = Insets().set_left_right(2, 4).set_top_bottom(-1, -3);
+ EXPECT_EQ(Outsets().set_left_right(-2, -4).set_top_bottom(1, 3),
+ insets.ToOutsets());
+ EXPECT_EQ(insets, insets.ToOutsets().ToInsets());
+}
+
+} // namespace gfx
diff --git a/ui/gfx/geometry/linear_gradient.cc b/ui/gfx/geometry/linear_gradient.cc
new file mode 100644
index 0000000..080a5d6
--- /dev/null
+++ b/ui/gfx/geometry/linear_gradient.cc
@@ -0,0 +1,88 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/linear_gradient.h"
+
+#include <sstream>
+
+#include "base/check_op.h"
+#include "base/containers/adapters.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "ui/gfx/geometry/angle_conversions.h"
+#include "ui/gfx/geometry/axis_transform2d.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/transform.h"
+
+namespace gfx {
+
+// static
+LinearGradient& LinearGradient::GetEmpty() {
+ static LinearGradient kEmpty;
+ return kEmpty;
+}
+
+LinearGradient::LinearGradient() = default;
+
+LinearGradient::LinearGradient(int16_t angle) : angle_(angle) {}
+
+LinearGradient::LinearGradient(const LinearGradient& copy) = default;
+
+void LinearGradient::AddStep(float fraction, uint8_t alpha) {
+ DCHECK_LT(step_count_, kMaxStepSize);
+ DCHECK_GE(fraction, 0);
+ DCHECK_LE(fraction, 1);
+ // make sure the step's fraction is monotonically increasing.
+ DCHECK(step_count_ ? steps_[step_count_ - 1].fraction < fraction : true)
+ << base::StringPrintf("prev[%zu]=%f, next[%zu]=%f", step_count_ - 1,
+ steps_[step_count_ - 1].fraction, step_count_,
+ fraction);
+ steps_[step_count_].fraction = fraction;
+ steps_[step_count_++].alpha = alpha;
+}
+
+void LinearGradient::ReverseSteps() {
+ std::reverse(steps_.begin(), steps_.end());
+ std::rotate(steps_.begin(), steps_.end() - step_count_, steps_.end());
+ for (size_t i = 0; i < step_count_; i++)
+ steps_[i].fraction = 1.f - steps_[i].fraction;
+}
+
+void LinearGradient::ApplyTransform(const Transform& transform) {
+ if (transform.IsIdentityOrTranslation())
+ return;
+
+ float radian = DegToRad(static_cast<float>(angle_));
+ float y = -sin(radian);
+ float x = cos(radian);
+ PointF origin = transform.MapPoint(PointF());
+ PointF end = transform.MapPoint(PointF(x, y));
+ Vector2dF diff = end - origin;
+ float new_angle = gfx::RadToDeg(atan2(diff.y(), diff.x()));
+ angle_ = -static_cast<int16_t>(std::round(new_angle));
+}
+
+void LinearGradient::ApplyTransform(const AxisTransform2d& transform) {
+ if (transform.scale().x() == transform.scale().y())
+ return;
+
+ float radian = DegToRad(static_cast<float>(angle_));
+ float y = -sin(radian) * transform.scale().y();
+ float x = cos(radian) * transform.scale().x();
+ float new_angle = gfx::RadToDeg(atan2(y, x));
+ angle_ = -static_cast<int16_t>(std::round(new_angle));
+}
+
+std::string LinearGradient::ToString() const {
+ std::string result = base::StringPrintf(
+ "LinearGradient{angle=%d, step_count=%zu [", angle_, step_count_);
+ for (size_t i = 0; i < step_count_; ++i) {
+ if (i)
+ result += " - ";
+ result += base::StringPrintf("%f:%u", steps_[i].fraction, steps_[i].alpha);
+ }
+ return result + "]}";
+}
+
+} // namespace gfx
diff --git a/ui/gfx/geometry/linear_gradient.h b/ui/gfx/geometry/linear_gradient.h
new file mode 100644
index 0000000..d327662
--- /dev/null
+++ b/ui/gfx/geometry/linear_gradient.h
@@ -0,0 +1,95 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_LINEAR_GRADIENT_H_
+#define UI_GFX_LINEAR_GRADIENT_H_
+
+#include <stdint.h>
+
+#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <string>
+
+#include "ui/gfx/geometry/geometry_skia_export.h"
+
+namespace gfx {
+
+class AxisTransform2d;
+class Transform;
+
+// A class that defines a linear gradient mask.
+// Up to 6 steps are supported.
+//
+// ex. Horizontal linear gradient that starts in the middle.
+// LinearGradient gradient(0);
+// gradient.AddStep(20, 0);
+// gradient.AddStep(30, 255);
+// gradient.AddStep(70, 255);
+// gradient.AddStep(80, 0);
+class GEOMETRY_SKIA_EXPORT LinearGradient {
+ public:
+ struct Step {
+ // Fraction that defines a position in diagonal, from 0 to 1.
+ float fraction = 0;
+ // Alpha, from 0 to 255.
+ uint8_t alpha = 0;
+ };
+ static LinearGradient& GetEmpty();
+
+ static constexpr size_t kMaxStepSize = 8;
+ using StepArray = std::array<Step, kMaxStepSize>;
+
+ LinearGradient();
+ explicit LinearGradient(int16_t angle);
+ LinearGradient(const LinearGradient& copy);
+ LinearGradient& operator=(const LinearGradient& gradient_mask) = default;
+
+ bool IsEmpty() const { return !step_count_; }
+
+ // Add a new step. Adding more than 6 results in DCHECK or ignored.
+ void AddStep(float fraction, uint8_t alpha);
+
+ // Get step information.
+ const StepArray& steps() const { return steps_; }
+ StepArray& steps() { return steps_; }
+ size_t step_count() const { return step_count_; }
+
+ // Gets/Sets an angle (in degrees).
+ int16_t angle() const { return angle_; }
+ void set_angle(int16_t degree) { angle_ = degree; }
+
+ // Reverse the steps.
+ void ReverseSteps();
+
+ // Transform the angle.
+ void ApplyTransform(const Transform& transform);
+ void ApplyTransform(const AxisTransform2d& transform);
+
+ std::string ToString() const;
+
+ private:
+ // angle in degrees.
+ int16_t angle_ = 0;
+ size_t step_count_ = 0;
+ StepArray steps_;
+};
+
+inline bool operator==(const LinearGradient::Step& lhs,
+ const LinearGradient::Step& rhs) {
+ return lhs.fraction == rhs.fraction && lhs.alpha == rhs.alpha;
+}
+
+inline bool operator==(const LinearGradient& lhs, const LinearGradient& rhs) {
+ return lhs.angle() == rhs.angle() && lhs.step_count() == rhs.step_count() &&
+ lhs.steps() == rhs.steps();
+}
+
+inline bool operator!=(const LinearGradient& lhs, const LinearGradient& rhs) {
+ return !(lhs == rhs);
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_LINEAR_GRADIENT_H_
diff --git a/ui/gfx/geometry/linear_gradient_unittest.cc b/ui/gfx/geometry/linear_gradient_unittest.cc
new file mode 100644
index 0000000..fab4a44
--- /dev/null
+++ b/ui/gfx/geometry/linear_gradient_unittest.cc
@@ -0,0 +1,112 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/linear_gradient.h"
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/axis_transform2d.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/transform.h"
+
+namespace gfx {
+
+TEST(LinearGradientTest, Basic) {
+ LinearGradient gradient(45);
+ EXPECT_TRUE(gradient.IsEmpty());
+
+ gradient.AddStep(.1, 0);
+ gradient.AddStep(.5, 50);
+ gradient.AddStep(.8, 1);
+
+ EXPECT_FALSE(gradient.IsEmpty());
+ EXPECT_EQ(45, gradient.angle());
+ EXPECT_EQ(3u, gradient.step_count());
+ EXPECT_FLOAT_EQ(gradient.steps()[0].fraction, .1);
+ EXPECT_EQ(gradient.steps()[0].alpha, 0);
+ EXPECT_FLOAT_EQ(gradient.steps()[1].fraction, .5);
+ EXPECT_EQ(gradient.steps()[1].alpha, 50);
+ EXPECT_FLOAT_EQ(gradient.steps()[2].fraction, .8);
+ EXPECT_EQ(gradient.steps()[2].alpha, 1);
+
+ LinearGradient gradient2(90);
+ gradient2.AddStep(.1, 0);
+ gradient2.AddStep(.5, 50);
+ gradient2.AddStep(.8, 1);
+
+ EXPECT_NE(gradient, gradient2);
+
+ gradient2.set_angle(45);
+ EXPECT_EQ(gradient, gradient2);
+
+ gradient2.AddStep(.9, 0);
+ EXPECT_NE(gradient, gradient2);
+}
+
+TEST(LinearGradientTest, Reverse) {
+ LinearGradient gradient(45);
+ // Make sure reversing an empty LinearGradient doesn't cause an issue.
+ gradient.ReverseSteps();
+
+ gradient.AddStep(.1, 0);
+ gradient.AddStep(.5, 50);
+ gradient.AddStep(.8, 1);
+
+ gradient.ReverseSteps();
+
+ EXPECT_EQ(45, gradient.angle());
+ EXPECT_EQ(3u, gradient.step_count());
+
+ EXPECT_FLOAT_EQ(gradient.steps()[0].fraction, .2);
+ EXPECT_EQ(gradient.steps()[0].alpha, 1);
+ EXPECT_FLOAT_EQ(gradient.steps()[1].fraction, .5);
+ EXPECT_EQ(gradient.steps()[1].alpha, 50);
+ EXPECT_FLOAT_EQ(gradient.steps()[2].fraction, .9);
+ EXPECT_EQ(gradient.steps()[2].alpha, 0);
+}
+
+TEST(LinearGradientTest, ApplyTransform) {
+ {
+ LinearGradient gradient(45);
+ gfx::Transform transform;
+ transform.Translate(10, 50);
+ gradient.ApplyTransform(transform);
+ EXPECT_EQ(45, gradient.angle());
+ }
+ // Scale can change the angle.
+ {
+ LinearGradient gradient(45);
+ gfx::Transform transform;
+ transform.Scale(1, 10);
+ gradient.ApplyTransform(transform);
+ EXPECT_EQ(84, gradient.angle());
+ }
+ {
+ LinearGradient gradient(45);
+ gfx::Transform transform;
+ transform.Rotate(45);
+ gradient.ApplyTransform(transform);
+ EXPECT_EQ(0, gradient.angle());
+ }
+}
+
+TEST(LinearGradientTest, ApplyAxisTransform2d) {
+ {
+ LinearGradient gradient(45);
+ auto transform = AxisTransform2d::FromScaleAndTranslation(
+ Vector2dF(1, 1), Vector2dF(10, 50));
+ gradient.ApplyTransform(transform);
+ EXPECT_EQ(45, gradient.angle());
+ }
+ // Scale can change the angle.
+ {
+ LinearGradient gradient(45);
+ auto transform = AxisTransform2d::FromScaleAndTranslation(
+ Vector2dF(1, 10), Vector2dF(10, 50));
+ gradient.ApplyTransform(transform);
+ EXPECT_EQ(84, gradient.angle());
+ }
+}
+
+} // namespace gfx
diff --git a/ui/gfx/geometry/mask_filter_info.cc b/ui/gfx/geometry/mask_filter_info.cc
index 9757acd..fceff3e 100644
--- a/ui/gfx/geometry/mask_filter_info.cc
+++ b/ui/gfx/geometry/mask_filter_info.cc
@@ -1,23 +1,74 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/mask_filter_info.h"
-#include <sstream>
-
+#include "ui/gfx/geometry/axis_transform2d.h"
+#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/geometry/transform.h"
namespace gfx {
-bool MaskFilterInfo::Transform(const gfx::Transform& transform) {
- return rounded_corner_bounds_.IsEmpty()
- ? false
- : transform.TransformRRectF(&rounded_corner_bounds_);
+void MaskFilterInfo::ApplyTransform(const Transform& transform) {
+ if (rounded_corner_bounds_.IsEmpty()) {
+ return;
+ }
+
+ // We want this to fail only in cases where our
+ // Transform::Preserves2dAxisAlignment() returns false. However,
+ // SkMatrix::preservesAxisAlignment() is stricter (it lacks the kEpsilon
+ // test). So after converting our Matrix44 to SkMatrix, round
+ // relevant values less than kEpsilon to zero.
+ constexpr float kEpsilon = std::numeric_limits<float>::epsilon();
+ SkMatrix rounded_matrix = TransformToFlattenedSkMatrix(transform);
+ if (std::abs(rounded_matrix.get(SkMatrix::kMScaleX)) < kEpsilon)
+ rounded_matrix.set(SkMatrix::kMScaleX, 0.0f);
+ if (std::abs(rounded_matrix.get(SkMatrix::kMSkewX)) < kEpsilon)
+ rounded_matrix.set(SkMatrix::kMSkewX, 0.0f);
+ if (std::abs(rounded_matrix.get(SkMatrix::kMSkewY)) < kEpsilon)
+ rounded_matrix.set(SkMatrix::kMSkewY, 0.0f);
+ if (std::abs(rounded_matrix.get(SkMatrix::kMScaleY)) < kEpsilon)
+ rounded_matrix.set(SkMatrix::kMScaleY, 0.0f);
+
+ SkRRect new_rect;
+ if (!SkRRect(rounded_corner_bounds_).transform(rounded_matrix, &new_rect) ||
+ !new_rect.isValid()) {
+ rounded_corner_bounds_ = RRectF();
+ return;
+ }
+ rounded_corner_bounds_ = RRectF(new_rect);
+
+ if (gradient_mask_ && !gradient_mask_->IsEmpty()) {
+ gradient_mask_->ApplyTransform(transform);
+ }
+}
+
+void MaskFilterInfo::ApplyTransform(const AxisTransform2d& transform) {
+ if (rounded_corner_bounds_.IsEmpty())
+ return;
+
+ rounded_corner_bounds_.Scale(transform.scale().x(), transform.scale().y());
+ rounded_corner_bounds_.Offset(transform.translation());
+ if (!SkRRect(rounded_corner_bounds_).isValid()) {
+ rounded_corner_bounds_ = RRectF();
+ return;
+ }
+
+ if (gradient_mask_ && !gradient_mask_->IsEmpty()) {
+ gradient_mask_->ApplyTransform(transform);
+ }
}
std::string MaskFilterInfo::ToString() const {
- return "MaskFilterInfo{" + rounded_corner_bounds_.ToString() + "}";
+ std::string result = "MaskFilterInfo{" + rounded_corner_bounds_.ToString();
+
+ if (gradient_mask_)
+ result += ", gradient_mask=" + gradient_mask_->ToString();
+
+ result += "}";
+
+ return result;
}
} // namespace gfx
diff --git a/ui/gfx/geometry/mask_filter_info.h b/ui/gfx/geometry/mask_filter_info.h
index c796b49..05dde5e 100644
--- a/ui/gfx/geometry/mask_filter_info.h
+++ b/ui/gfx/geometry/mask_filter_info.h
@@ -1,16 +1,19 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_GEOMETRY_MASK_FILTER_INFO_H_
#define UI_GFX_GEOMETRY_MASK_FILTER_INFO_H_
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/geometry_skia_export.h"
+#include "ui/gfx/geometry/linear_gradient.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/rrect_f.h"
namespace gfx {
+class AxisTransform2d;
class Transform;
// This class defines a mask filter to be applied to the given rect.
@@ -19,8 +22,12 @@
MaskFilterInfo() = default;
explicit MaskFilterInfo(const RRectF& rrect)
: rounded_corner_bounds_(rrect) {}
- MaskFilterInfo(const RectF& bounds, const RoundedCornersF& radii)
- : rounded_corner_bounds_(bounds, radii) {}
+ MaskFilterInfo(const RRectF& rrect, const gfx::LinearGradient& gradient_mask)
+ : rounded_corner_bounds_(rrect), gradient_mask_(gradient_mask) {}
+ MaskFilterInfo(const RectF& bounds,
+ const RoundedCornersF& radii,
+ const gfx::LinearGradient& gradient_mask)
+ : rounded_corner_bounds_(bounds, radii), gradient_mask_(gradient_mask) {}
MaskFilterInfo(const MaskFilterInfo& copy) = default;
~MaskFilterInfo() = default;
@@ -36,12 +43,26 @@
rounded_corner_bounds_.GetType() != RRectF::Type::kRect;
}
+ const absl::optional<gfx::LinearGradient>& gradient_mask() const {
+ return gradient_mask_;
+ }
+
+ // True if this contains an effective gradient mask (requires filter bounds).
+ bool HasGradientMask() const {
+ if (rounded_corner_bounds_.IsEmpty())
+ return false;
+
+ return gradient_mask_ && !gradient_mask_->IsEmpty();
+ }
+
// True if this contains no effective mask information.
bool IsEmpty() const { return rounded_corner_bounds_.IsEmpty(); }
- // Transform the mask information. Returns false if the transform
- // cannot be applied.
- bool Transform(const gfx::Transform& transform);
+ // Transform the mask filter information. If the transform cannot be applied
+ // (e.g. it would make rounded_corner_bounds_ invalid), rounded_corner_bounds_
+ // will be set to empty.
+ void ApplyTransform(const Transform& transform);
+ void ApplyTransform(const AxisTransform2d& transform);
std::string ToString() const;
@@ -49,16 +70,25 @@
// The rounded corner bounds. This also defines the bounds that the mask
// filter will be applied to.
RRectF rounded_corner_bounds_;
+
+ // Shader based linear gradient mask to be applied to a layer.
+ absl::optional<gfx::LinearGradient> gradient_mask_;
};
inline bool operator==(const MaskFilterInfo& lhs, const MaskFilterInfo& rhs) {
- return lhs.rounded_corner_bounds() == rhs.rounded_corner_bounds();
+ return (lhs.rounded_corner_bounds() == rhs.rounded_corner_bounds()) &&
+ (lhs.gradient_mask() == rhs.gradient_mask());
}
inline bool operator!=(const MaskFilterInfo& lhs, const MaskFilterInfo& rhs) {
return !(lhs == rhs);
}
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const MaskFilterInfo&, ::std::ostream* os);
+
} // namespace gfx
#endif // UI_GFX_GEOMETRY_MASK_FILTER_INFO_H_
diff --git a/ui/gfx/geometry/mask_filter_info_unittest.cc b/ui/gfx/geometry/mask_filter_info_unittest.cc
new file mode 100644
index 0000000..a147fe4
--- /dev/null
+++ b/ui/gfx/geometry/mask_filter_info_unittest.cc
@@ -0,0 +1,120 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/mask_filter_info.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/axis_transform2d.h"
+#include "ui/gfx/geometry/rrect_f.h"
+#include "ui/gfx/geometry/transform.h"
+
+namespace gfx {
+namespace {
+
+LinearGradient CreateGradient(int angle) {
+ LinearGradient gradient(angle);
+ gradient.AddStep(0.5, 50);
+ return gradient;
+}
+
+TEST(MaskFilterInfoTest, ApplyTransform) {
+ MaskFilterInfo info(RRectF(1.f, 2.f, 20.f, 25.f, 5.f));
+ MaskFilterInfo expected = info;
+ info.ApplyTransform(Transform());
+ EXPECT_EQ(expected, info);
+
+ auto translation = Transform::MakeTranslation(-3.5f, 7.75f);
+ expected = MaskFilterInfo(RRectF(-2.5f, 9.75f, 20.f, 25.f, 5.f));
+ info.ApplyTransform(translation);
+ EXPECT_EQ(expected, info);
+
+ info = MaskFilterInfo(RRectF(1.f, 2.f, 20.f, 25.f, 5.f), CreateGradient(50));
+ expected =
+ MaskFilterInfo(RRectF(-2.5f, 9.75f, 20.f, 25.f, 5.f), CreateGradient(50));
+ info.ApplyTransform(translation);
+ EXPECT_EQ(expected, info);
+
+ auto rotation_90_clock = Transform::Make90degRotation();
+ info = MaskFilterInfo(
+ RRectF(RectF(0, 0, 20.f, 25.f), 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f),
+ CreateGradient(50));
+ expected = MaskFilterInfo(RRectF(RectF(-25.f, 0, 25.f, 20.f), 8.f, 7.f, 2.f,
+ 1.f, 4.f, 3.f, 6.f, 5.f),
+ CreateGradient(-40));
+ info.ApplyTransform(rotation_90_clock);
+ EXPECT_EQ(expected, info);
+
+ Transform rotation_90_unrounded;
+ rotation_90_unrounded.Rotate(90.0 + 1e-10);
+ info = MaskFilterInfo(
+ RRectF(RectF(0, 0, 20.f, 25.f), 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f),
+ CreateGradient(50));
+ EXPECT_TRUE(rotation_90_unrounded.Preserves2dAxisAlignment());
+ info.ApplyTransform(rotation_90_unrounded);
+ EXPECT_EQ(expected, info);
+
+ auto scale = Transform::MakeScale(2.f, 3.f);
+ info = MaskFilterInfo(
+ RRectF(RectF(0, 0, 20.f, 25.f), 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f),
+ CreateGradient(50));
+ expected = MaskFilterInfo(RRectF(RectF(0, 0, 40.f, 75.f), 2.f, 6.f, 6.f, 12.f,
+ 10.f, 18.f, 14.f, 24.f),
+ CreateGradient(61));
+ info.ApplyTransform(scale);
+ EXPECT_EQ(expected, info);
+
+ Transform rotation;
+ rotation.Rotate(45);
+ info.ApplyTransform(rotation);
+ EXPECT_TRUE(info.IsEmpty());
+}
+
+TEST(MaskFilterInfoTest, ApplyAxisTransform2d) {
+ MaskFilterInfo info(
+ RRectF(RectF(0, 0, 20.f, 25.f), 1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f),
+ CreateGradient(50));
+ MaskFilterInfo expected = info;
+ info.ApplyTransform(AxisTransform2d());
+ EXPECT_EQ(expected, info);
+
+ MaskFilterInfo scaled = info;
+ expected = MaskFilterInfo(RRectF(RectF(0, 0, 40.f, 75.f), 2.f, 6.f, 6.f, 12.f,
+ 10.f, 18.f, 14.f, 24.f),
+ CreateGradient(61));
+ scaled.ApplyTransform(AxisTransform2d::FromScaleAndTranslation(
+ Vector2dF(2.f, 3.f), Vector2dF()));
+ EXPECT_EQ(expected, scaled);
+
+ MaskFilterInfo scaled_translated = scaled;
+ expected = MaskFilterInfo(RRectF(RectF(-3.5f, 7.75f, 40.f, 75.f), 2.f, 6.f,
+ 6.f, 12.f, 10.f, 18.f, 14.f, 24.f),
+ CreateGradient(61));
+ scaled_translated.ApplyTransform(AxisTransform2d::FromScaleAndTranslation(
+ Vector2dF(1.f, 1.f), Vector2dF(-3.5f, 7.75f)));
+ EXPECT_EQ(expected, scaled_translated);
+
+ MaskFilterInfo scaled_translated_2 = info;
+ scaled_translated_2.ApplyTransform(AxisTransform2d::FromScaleAndTranslation(
+ Vector2dF(2.f, 3.f), Vector2dF(-3.5f, 7.75f)));
+ EXPECT_EQ(expected, scaled_translated_2);
+
+ const float kInf = std::numeric_limits<float>::infinity();
+ const float kNan = std::numeric_limits<float>::quiet_NaN();
+ auto failure_is_empty = [&](const AxisTransform2d& transform) {
+ MaskFilterInfo transformed = info;
+ transformed.ApplyTransform(transform);
+ return transformed.IsEmpty();
+ };
+ EXPECT_TRUE(failure_is_empty(AxisTransform2d::FromScaleAndTranslation(
+ Vector2dF(kInf, 1), Vector2dF(1, 1))));
+ EXPECT_TRUE(failure_is_empty(AxisTransform2d::FromScaleAndTranslation(
+ Vector2dF(kNan, 1), Vector2dF(1, 1))));
+ EXPECT_TRUE(failure_is_empty(AxisTransform2d::FromScaleAndTranslation(
+ Vector2dF(1, 1), Vector2dF(1, kInf))));
+ EXPECT_TRUE(failure_is_empty(AxisTransform2d::FromScaleAndTranslation(
+ Vector2dF(1, 1), Vector2dF(1, kNan))));
+}
+
+} // anonymous namespace
+} // namespace gfx
diff --git a/ui/gfx/geometry/matrix3_f.cc b/ui/gfx/geometry/matrix3_f.cc
index afacbea..a63e867 100644
--- a/ui/gfx/geometry/matrix3_f.cc
+++ b/ui/gfx/geometry/matrix3_f.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/matrix3_f.h b/ui/gfx/geometry/matrix3_f.h
index 0b5cc12..e1d230e 100644
--- a/ui/gfx/geometry/matrix3_f.h
+++ b/ui/gfx/geometry/matrix3_f.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/matrix3_unittest.cc b/ui/gfx/geometry/matrix3_unittest.cc
index 1f550e8..289a82e 100644
--- a/ui/gfx/geometry/matrix3_unittest.cc
+++ b/ui/gfx/geometry/matrix3_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/matrix44.cc b/ui/gfx/geometry/matrix44.cc
new file mode 100644
index 0000000..29844c5
--- /dev/null
+++ b/ui/gfx/geometry/matrix44.cc
@@ -0,0 +1,745 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/matrix44.h"
+
+#include <algorithm>
+#include <cmath>
+#include <type_traits>
+#include <utility>
+
+#include "ui/gfx/geometry/decomposed_transform.h"
+
+namespace gfx {
+
+namespace {
+
+ALWAYS_INLINE Double4 SwapHighLow(Double4 v) {
+ return Double4{v[2], v[3], v[0], v[1]};
+}
+
+ALWAYS_INLINE Double4 SwapInPairs(Double4 v) {
+ return Double4{v[1], v[0], v[3], v[2]};
+}
+
+// This is based on
+// https://github.com/niswegmann/small-matrix-inverse/blob/master/invert4x4_llvm.h,
+// which is based on Intel AP-928 "Streaming SIMD Extensions - Inverse of 4x4
+// Matrix": https://drive.google.com/file/d/0B9rh9tVI0J5mX1RUam5nZm85OFE/view.
+ALWAYS_INLINE bool InverseWithDouble4Cols(Double4& c0,
+ Double4& c1,
+ Double4& c2,
+ Double4& c3) {
+ // Note that r1 and r3 have components 2/3 and 0/1 swapped.
+ Double4 r0 = {c0[0], c1[0], c2[0], c3[0]};
+ Double4 r1 = {c2[1], c3[1], c0[1], c1[1]};
+ Double4 r2 = {c0[2], c1[2], c2[2], c3[2]};
+ Double4 r3 = {c2[3], c3[3], c0[3], c1[3]};
+
+ Double4 t = SwapInPairs(r2 * r3);
+ c0 = r1 * t;
+ c1 = r0 * t;
+
+ t = SwapHighLow(t);
+ c0 = r1 * t - c0;
+ c1 = SwapHighLow(r0 * t - c1);
+
+ t = SwapInPairs(r1 * r2);
+ c0 += r3 * t;
+ c3 = r0 * t;
+
+ t = SwapHighLow(t);
+ c0 -= r3 * t;
+ c3 = SwapHighLow(r0 * t - c3);
+
+ t = SwapInPairs(SwapHighLow(r1) * r3);
+ r2 = SwapHighLow(r2);
+ c0 += r2 * t;
+ c2 = r0 * t;
+
+ t = SwapHighLow(t);
+ c0 -= r2 * t;
+
+ double det = Sum(r0 * c0);
+ if (!std::isnormal(static_cast<float>(det)))
+ return false;
+
+ c2 = SwapHighLow(r0 * t - c2);
+
+ t = SwapInPairs(r0 * r1);
+ c2 = r3 * t + c2;
+ c3 = r2 * t - c3;
+
+ t = SwapHighLow(t);
+ c2 = r3 * t - c2;
+ c3 -= r2 * t;
+
+ t = SwapInPairs(r0 * r3);
+ c1 -= r2 * t;
+ c2 = r1 * t + c2;
+
+ t = SwapHighLow(t);
+ c1 = r2 * t + c1;
+ c2 -= r1 * t;
+
+ t = SwapInPairs(r0 * r2);
+ c1 = r3 * t + c1;
+ c3 -= r1 * t;
+
+ t = SwapHighLow(t);
+ c1 -= r3 * t;
+ c3 = r1 * t + c3;
+
+ det = 1.0 / det;
+ c0 *= det;
+ c1 *= det;
+ c2 *= det;
+ c3 *= det;
+ return true;
+}
+
+} // anonymous namespace
+
+void Matrix44::GetColMajor(double dst[16]) const {
+ const double* src = &matrix_[0][0];
+ std::copy(src, src + 16, dst);
+}
+
+void Matrix44::GetColMajorF(float dst[16]) const {
+ const double* src = &matrix_[0][0];
+ std::copy(src, src + 16, dst);
+}
+
+void Matrix44::PreTranslate(double dx, double dy) {
+ SetCol(3, Col(0) * dx + Col(1) * dy + Col(3));
+}
+
+void Matrix44::PreTranslate3d(double dx, double dy, double dz) {
+ if (AllTrue(Double4{dx, dy, dz, 0} == Double4{0, 0, 0, 0}))
+ return;
+
+ SetCol(3, Col(0) * dx + Col(1) * dy + Col(2) * dz + Col(3));
+}
+
+void Matrix44::PostTranslate(double dx, double dy) {
+ if (LIKELY(!HasPerspective())) {
+ matrix_[3][0] += dx;
+ matrix_[3][1] += dy;
+ } else {
+ if (dx != 0) {
+ matrix_[0][0] += matrix_[0][3] * dx;
+ matrix_[1][0] += matrix_[1][3] * dx;
+ matrix_[2][0] += matrix_[2][3] * dx;
+ matrix_[3][0] += matrix_[3][3] * dx;
+ }
+ if (dy != 0) {
+ matrix_[0][1] += matrix_[0][3] * dy;
+ matrix_[1][1] += matrix_[1][3] * dy;
+ matrix_[2][1] += matrix_[2][3] * dy;
+ matrix_[3][1] += matrix_[3][3] * dy;
+ }
+ }
+}
+
+void Matrix44::PostTranslate3d(double dx, double dy, double dz) {
+ Double4 t{dx, dy, dz, 0};
+ if (AllTrue(t == Double4{0, 0, 0, 0}))
+ return;
+
+ if (LIKELY(!HasPerspective())) {
+ SetCol(3, Col(3) + t);
+ } else {
+ for (int i = 0; i < 4; ++i)
+ SetCol(i, Col(i) + t * matrix_[i][3]);
+ }
+}
+
+void Matrix44::PreScale(double sx, double sy) {
+ SetCol(0, Col(0) * sx);
+ SetCol(1, Col(1) * sy);
+}
+
+void Matrix44::PreScale3d(double sx, double sy, double sz) {
+ if (AllTrue(Double4{sx, sy, sz, 1} == Double4{1, 1, 1, 1}))
+ return;
+
+ SetCol(0, Col(0) * sx);
+ SetCol(1, Col(1) * sy);
+ SetCol(2, Col(2) * sz);
+}
+
+void Matrix44::PostScale(double sx, double sy) {
+ if (sx != 1) {
+ matrix_[0][0] *= sx;
+ matrix_[1][0] *= sx;
+ matrix_[2][0] *= sx;
+ matrix_[3][0] *= sx;
+ }
+ if (sy != 1) {
+ matrix_[0][1] *= sy;
+ matrix_[1][1] *= sy;
+ matrix_[2][1] *= sy;
+ matrix_[3][1] *= sy;
+ }
+}
+
+void Matrix44::PostScale3d(double sx, double sy, double sz) {
+ if (AllTrue(Double4{sx, sy, sz, 1} == Double4{1, 1, 1, 1}))
+ return;
+
+ Double4 s{sx, sy, sz, 1};
+ for (int i = 0; i < 4; i++)
+ SetCol(i, Col(i) * s);
+}
+
+void Matrix44::RotateUnitSinCos(double x,
+ double y,
+ double z,
+ double sin_angle,
+ double cos_angle) {
+ // Optimize cases where the axis is along a major axis. Since we've already
+ // normalized the vector we don't need to check that the other two dimensions
+ // are zero. Tiny errors of the other two dimensions are ignored.
+ if (z == 1.0) {
+ RotateAboutZAxisSinCos(sin_angle, cos_angle);
+ return;
+ }
+ if (y == 1.0) {
+ RotateAboutYAxisSinCos(sin_angle, cos_angle);
+ return;
+ }
+ if (x == 1.0) {
+ RotateAboutXAxisSinCos(sin_angle, cos_angle);
+ return;
+ }
+
+ double c = cos_angle;
+ double s = sin_angle;
+ double C = 1 - c;
+ double xs = x * s;
+ double ys = y * s;
+ double zs = z * s;
+ double xC = x * C;
+ double yC = y * C;
+ double zC = z * C;
+ double xyC = x * yC;
+ double yzC = y * zC;
+ double zxC = z * xC;
+
+ PreConcat(Matrix44(x * xC + c, xyC + zs, zxC - ys, 0, // col 0
+ xyC - zs, y * yC + c, yzC + xs, 0, // col 1
+ zxC + ys, yzC - xs, z * zC + c, 0, // col 2
+ 0, 0, 0, 1)); // col 3
+}
+
+void Matrix44::RotateAboutXAxisSinCos(double sin_angle, double cos_angle) {
+ Double4 c1 = Col(1);
+ Double4 c2 = Col(2);
+ SetCol(1, c1 * cos_angle + c2 * sin_angle);
+ SetCol(2, c2 * cos_angle - c1 * sin_angle);
+}
+
+void Matrix44::RotateAboutYAxisSinCos(double sin_angle, double cos_angle) {
+ Double4 c0 = Col(0);
+ Double4 c2 = Col(2);
+ SetCol(0, c0 * cos_angle - c2 * sin_angle);
+ SetCol(2, c2 * cos_angle + c0 * sin_angle);
+}
+
+void Matrix44::RotateAboutZAxisSinCos(double sin_angle, double cos_angle) {
+ Double4 c0 = Col(0);
+ Double4 c1 = Col(1);
+ SetCol(0, c0 * cos_angle + c1 * sin_angle);
+ SetCol(1, c1 * cos_angle - c0 * sin_angle);
+}
+
+void Matrix44::Skew(double tan_skew_x, double tan_skew_y) {
+ Double4 c0 = Col(0);
+ Double4 c1 = Col(1);
+ SetCol(0, c0 + c1 * tan_skew_y);
+ SetCol(1, c1 + c0 * tan_skew_x);
+}
+
+void Matrix44::ApplyDecomposedSkews(const double skews[3]) {
+ Double4 c0 = Col(0);
+ Double4 c1 = Col(1);
+ Double4 c2 = Col(2);
+ // / |1 0 0 0| |1 0 s1 0| |1 s0 0 0| |1 s0 s1 0| \
+ // |c0 c1 c2 c3| * | |0 1 s2 0| * |0 1 0 0| * |0 1 0 0| = |0 1 s2 0| |
+ // | |0 0 1 0| |0 0 1 0| |0 0 1 0| |0 0 1 0| |
+ // \ |0 0 0 1| |0 0 0 1| |0 0 0 1| |0 0 0 1| /
+ SetCol(1, c1 + c0 * skews[0]);
+ SetCol(2, c0 * skews[1] + c1 * skews[2] + c2);
+}
+
+void Matrix44::ApplyPerspectiveDepth(double perspective) {
+ DCHECK_NE(perspective, 0.0);
+ SetCol(2, Col(2) + Col(3) * (-1.0 / perspective));
+}
+
+void Matrix44::SetConcat(const Matrix44& x, const Matrix44& y) {
+ if (x.Is2dTransform() && y.Is2dTransform()) {
+ double a = x.matrix_[0][0];
+ double b = x.matrix_[0][1];
+ double c = x.matrix_[1][0];
+ double d = x.matrix_[1][1];
+ double e = x.matrix_[3][0];
+ double f = x.matrix_[3][1];
+ double ya = y.matrix_[0][0];
+ double yb = y.matrix_[0][1];
+ double yc = y.matrix_[1][0];
+ double yd = y.matrix_[1][1];
+ double ye = y.matrix_[3][0];
+ double yf = y.matrix_[3][1];
+ *this = Matrix44(a * ya + c * yb, b * ya + d * yb, 0, 0, // col 0
+ a * yc + c * yd, b * yc + d * yd, 0, 0, // col 1
+ 0, 0, 1, 0, // col 2
+ a * ye + c * yf + e, b * ye + d * yf + f, 0, 1); // col 3
+ return;
+ }
+
+ auto c0 = x.Col(0);
+ auto c1 = x.Col(1);
+ auto c2 = x.Col(2);
+ auto c3 = x.Col(3);
+
+ auto mc0 = y.Col(0);
+ auto mc1 = y.Col(1);
+ auto mc2 = y.Col(2);
+ auto mc3 = y.Col(3);
+
+ SetCol(0, c0 * mc0[0] + c1 * mc0[1] + c2 * mc0[2] + c3 * mc0[3]);
+ SetCol(1, c0 * mc1[0] + c1 * mc1[1] + c2 * mc1[2] + c3 * mc1[3]);
+ SetCol(2, c0 * mc2[0] + c1 * mc2[1] + c2 * mc2[2] + c3 * mc2[3]);
+ SetCol(3, c0 * mc3[0] + c1 * mc3[1] + c2 * mc3[2] + c3 * mc3[3]);
+}
+
+bool Matrix44::GetInverse(Matrix44& result) const {
+ if (Is2dTransform()) {
+ double determinant = Determinant();
+ if (!std::isnormal(static_cast<float>(determinant)))
+ return false;
+
+ double inv_det = 1.0 / determinant;
+ double a = matrix_[0][0];
+ double b = matrix_[0][1];
+ double c = matrix_[1][0];
+ double d = matrix_[1][1];
+ double e = matrix_[3][0];
+ double f = matrix_[3][1];
+ result = Matrix44(d * inv_det, -b * inv_det, 0, 0, // col 0
+ -c * inv_det, a * inv_det, 0, 0, // col 1
+ 0, 0, 1, 0, // col 2
+ (c * f - d * e) * inv_det, (b * e - a * f) * inv_det, 0,
+ 1); // col 3
+ return true;
+ }
+
+ Double4 c0 = Col(0);
+ Double4 c1 = Col(1);
+ Double4 c2 = Col(2);
+ Double4 c3 = Col(3);
+
+ if (!InverseWithDouble4Cols(c0, c1, c2, c3))
+ return false;
+
+ result.SetCol(0, c0);
+ result.SetCol(1, c1);
+ result.SetCol(2, c2);
+ result.SetCol(3, c3);
+ return true;
+}
+
+bool Matrix44::IsInvertible() const {
+ return std::isnormal(static_cast<float>(Determinant()));
+}
+
+// This is a simplified version of InverseWithDouble4Cols().
+double Matrix44::Determinant() const {
+ if (Is2dTransform())
+ return matrix_[0][0] * matrix_[1][1] - matrix_[0][1] * matrix_[1][0];
+
+ Double4 c0 = Col(0);
+ Double4 c1 = Col(1);
+ Double4 c2 = Col(2);
+ Double4 c3 = Col(3);
+
+ // Note that r1 and r3 have components 2/3 and 0/1 swapped.
+ Double4 r0 = {c0[0], c1[0], c2[0], c3[0]};
+ Double4 r1 = {c2[1], c3[1], c0[1], c1[1]};
+ Double4 r2 = {c0[2], c1[2], c2[2], c3[2]};
+ Double4 r3 = {c2[3], c3[3], c0[3], c1[3]};
+
+ Double4 t = SwapInPairs(r2 * r3);
+ c0 = r1 * t;
+ t = SwapHighLow(t);
+ c0 = r1 * t - c0;
+ t = SwapInPairs(r1 * r2);
+ c0 += r3 * t;
+ t = SwapHighLow(t);
+ c0 -= r3 * t;
+ t = SwapInPairs(SwapHighLow(r1) * r3);
+ r2 = SwapHighLow(r2);
+ c0 += r2 * t;
+ t = SwapHighLow(t);
+ c0 -= r2 * t;
+
+ return Sum(r0 * c0);
+}
+
+void Matrix44::Transpose() {
+ using std::swap;
+ swap(matrix_[0][1], matrix_[1][0]);
+ swap(matrix_[0][2], matrix_[2][0]);
+ swap(matrix_[0][3], matrix_[3][0]);
+ swap(matrix_[1][2], matrix_[2][1]);
+ swap(matrix_[1][3], matrix_[3][1]);
+ swap(matrix_[2][3], matrix_[3][2]);
+}
+
+void Matrix44::Zoom(double zoom_factor) {
+ matrix_[0][3] /= zoom_factor;
+ matrix_[1][3] /= zoom_factor;
+ matrix_[2][3] /= zoom_factor;
+ matrix_[3][0] *= zoom_factor;
+ matrix_[3][1] *= zoom_factor;
+ matrix_[3][2] *= zoom_factor;
+}
+
+double Matrix44::MapVector2(double vec[2]) const {
+ double v0 = vec[0];
+ double v1 = vec[1];
+ double x = v0 * matrix_[0][0] + v1 * matrix_[1][0] + matrix_[3][0];
+ double y = v0 * matrix_[0][1] + v1 * matrix_[1][1] + matrix_[3][1];
+ double w = v0 * matrix_[0][3] + v1 * matrix_[1][3] + matrix_[3][3];
+ vec[0] = x;
+ vec[1] = y;
+ return w;
+}
+
+void Matrix44::MapVector4(double vec[4]) const {
+ Double4 v = LoadDouble4(vec);
+ Double4 r0{matrix_[0][0], matrix_[1][0], matrix_[2][0], matrix_[3][0]};
+ Double4 r1{matrix_[0][1], matrix_[1][1], matrix_[2][1], matrix_[3][1]};
+ Double4 r2{matrix_[0][2], matrix_[1][2], matrix_[2][2], matrix_[3][2]};
+ Double4 r3{matrix_[0][3], matrix_[1][3], matrix_[2][3], matrix_[3][3]};
+ StoreDouble4(Double4{Sum(r0 * v), Sum(r1 * v), Sum(r2 * v), Sum(r3 * v)},
+ vec);
+}
+
+void Matrix44::Flatten() {
+ matrix_[0][2] = 0;
+ matrix_[1][2] = 0;
+ matrix_[3][2] = 0;
+ SetCol(2, Double4{0, 0, 1, 0});
+}
+
+// TODO(crbug.com/1359528): Consider letting this function always succeed.
+absl::optional<DecomposedTransform> Matrix44::Decompose2d() const {
+ DCHECK(Is2dTransform());
+
+ // https://www.w3.org/TR/css-transforms-1/#decomposing-a-2d-matrix.
+ // Decompose a 2D transformation matrix of the form:
+ // [m11 m21 0 m41]
+ // [m12 m22 0 m42]
+ // [ 0 0 1 0 ]
+ // [ 0 0 0 1 ]
+ //
+ // The decomposition is of the form:
+ // M = translate * rotate * skew * scale
+ // [1 0 0 Tx] [cos(R) -sin(R) 0 0] [1 K 0 0] [Sx 0 0 0]
+ // = [0 1 0 Ty] [sin(R) cos(R) 0 0] [0 1 0 0] [0 Sy 0 0]
+ // [0 0 1 0 ] [ 0 0 1 0] [0 0 1 0] [0 0 1 0]
+ // [0 0 0 1 ] [ 0 0 0 1] [0 0 0 1] [0 0 0 1]
+
+ double m11 = matrix_[0][0];
+ double m21 = matrix_[1][0];
+ double m12 = matrix_[0][1];
+ double m22 = matrix_[1][1];
+
+ double determinant = m11 * m22 - m12 * m21;
+ // Test for matrix being singular.
+ if (determinant == 0)
+ return absl::nullopt;
+
+ DecomposedTransform decomp;
+
+ // Translation transform.
+ // [m11 m21 0 m41] [1 0 0 Tx] [m11 m21 0 0]
+ // [m12 m22 0 m42] = [0 1 0 Ty] [m12 m22 0 0]
+ // [ 0 0 1 0 ] [0 0 1 0 ] [ 0 0 1 0]
+ // [ 0 0 0 1 ] [0 0 0 1 ] [ 0 0 0 1]
+ decomp.translate[0] = matrix_[3][0];
+ decomp.translate[1] = matrix_[3][1];
+
+ // For the remainder of the decomposition process, we can focus on the upper
+ // 2x2 submatrix
+ // [m11 m21] = [cos(R) -sin(R)] [1 K] [Sx 0 ]
+ // [m12 m22] [sin(R) cos(R)] [0 1] [0 Sy]
+ // = [Sx*cos(R) Sy*(K*cos(R) - sin(R))]
+ // [Sx*sin(R) Sy*(K*sin(R) + cos(R))]
+
+ // Determine sign of the x and y scale.
+ if (determinant < 0) {
+ // If the determinant is negative, we need to flip either the x or y scale.
+ // Flipping both is equivalent to rotating by 180 degrees.
+ if (m11 < m22) {
+ decomp.scale[0] *= -1;
+ } else {
+ decomp.scale[1] *= -1;
+ }
+ }
+
+ // X Scale.
+ // m11^2 + m12^2 = Sx^2*(cos^2(R) + sin^2(R)) = Sx^2.
+ // Sx = +/-sqrt(m11^2 + m22^2)
+ decomp.scale[0] *= sqrt(m11 * m11 + m12 * m12);
+ m11 /= decomp.scale[0];
+ m12 /= decomp.scale[0];
+
+ // Post normalization, the submatrix is now of the form:
+ // [m11 m21] = [cos(R) Sy*(K*cos(R) - sin(R))]
+ // [m12 m22] [sin(R) Sy*(K*sin(R) + cos(R))]
+
+ // XY Shear.
+ // m11 * m21 + m12 * m22 = Sy*K*cos^2(R) - Sy*sin(R)*cos(R) +
+ // Sy*K*sin^2(R) + Sy*cos(R)*sin(R)
+ // = Sy*K
+ double scaled_shear = m11 * m21 + m12 * m22;
+ m21 -= m11 * scaled_shear;
+ m22 -= m12 * scaled_shear;
+
+ // Post normalization, the submatrix is now of the form:
+ // [m11 m21] = [cos(R) -Sy*sin(R)]
+ // [m12 m22] [sin(R) Sy*cos(R)]
+
+ // Y Scale.
+ // Similar process to determining x-scale.
+ decomp.scale[1] *= sqrt(m21 * m21 + m22 * m22);
+ m21 /= decomp.scale[1];
+ m22 /= decomp.scale[1];
+ decomp.skew[0] = scaled_shear / decomp.scale[1];
+
+ // Rotation transform.
+ // [1-2(yy+zz) 2(xy-zw) 2(xz+yw) ] [cos(R) -sin(R) 0]
+ // [2(xy+zw) 1-2(xx+zz) 2(yz-xw) ] = [sin(R) cos(R) 0]
+ // [2(xz-yw) 2*(yz+xw) 1-2(xx+yy)] [ 0 0 1]
+ // Comparing terms, we can conclude that x = y = 0.
+ // [1-2zz -2zw 0] [cos(R) -sin(R) 0]
+ // [ 2zw 1-2zz 0] = [sin(R) cos(R) 0]
+ // [ 0 0 1] [ 0 0 1]
+ // cos(R) = 1 - 2*z^2
+ // From the double angle formula: cos(2a) = 1 - 2 sin(a)^2
+ // cos(R) = 1 - 2*sin(R/2)^2 = 1 - 2*z^2 ==> z = sin(R/2)
+ // sin(R) = 2*z*w
+ // But sin(2a) = 2 sin(a) cos(a)
+ // sin(R) = 2 sin(R/2) cos(R/2) = 2*z*w ==> w = cos(R/2)
+ double angle = std::atan2(m12, m11);
+ decomp.quaternion.set_x(0);
+ decomp.quaternion.set_y(0);
+ decomp.quaternion.set_z(std::sin(0.5 * angle));
+ decomp.quaternion.set_w(std::cos(0.5 * angle));
+
+ return decomp;
+}
+
+absl::optional<DecomposedTransform> Matrix44::Decompose() const {
+ // See documentation of Transform::Decompose() for why we need the 2d branch.
+ if (Is2dTransform())
+ return Decompose2d();
+
+ // https://www.w3.org/TR/css-transforms-2/#decomposing-a-3d-matrix.
+
+ Double4 c0 = Col(0);
+ Double4 c1 = Col(1);
+ Double4 c2 = Col(2);
+ Double4 c3 = Col(3);
+
+ // Normalize the matrix.
+ if (!std::isnormal(c3[3]))
+ return absl::nullopt;
+
+ double inv_w = 1.0 / c3[3];
+ c0 *= inv_w;
+ c1 *= inv_w;
+ c2 *= inv_w;
+ c3 *= inv_w;
+
+ Double4 perspective = {c0[3], c1[3], c2[3], 1.0};
+ // Clear the perspective partition.
+ c0[3] = c1[3] = c2[3] = 0;
+ c3[3] = 1;
+
+ Double4 inverse_c0 = c0;
+ Double4 inverse_c1 = c1;
+ Double4 inverse_c2 = c2;
+ Double4 inverse_c3 = c3;
+ if (!InverseWithDouble4Cols(inverse_c0, inverse_c1, inverse_c2, inverse_c3))
+ return absl::nullopt;
+
+ DecomposedTransform decomp;
+
+ // First, isolate perspective.
+ if (!AllTrue(perspective == Double4{0, 0, 0, 1})) {
+ // Solve the equation by multiplying perspective by the inverse.
+ decomp.perspective[0] = gfx::Sum(perspective * inverse_c0);
+ decomp.perspective[1] = gfx::Sum(perspective * inverse_c1);
+ decomp.perspective[2] = gfx::Sum(perspective * inverse_c2);
+ decomp.perspective[3] = gfx::Sum(perspective * inverse_c3);
+ }
+
+ // Next take care of translation (easy).
+ decomp.translate[0] = c3[0];
+ c3[0] = 0;
+ decomp.translate[1] = c3[1];
+ c3[1] = 0;
+ decomp.translate[2] = c3[2];
+ c3[2] = 0;
+
+ // Note: Deviating from the spec in terms of variable naming. The matrix is
+ // stored on column major order and not row major. Using the variable 'row'
+ // instead of 'column' in the spec pseudocode has been the source of
+ // confusion, specifically in sorting out rotations.
+
+ // From now on, only the first 3 components of the Double4 column is used.
+ auto sum3 = [](Double4 c) -> double { return c[0] + c[1] + c[2]; };
+ auto extract_scale = [&sum3](Double4& c, double& scale) -> bool {
+ scale = std::sqrt(sum3(c * c));
+ if (!std::isnormal(scale))
+ return false;
+ c *= 1.0 / scale;
+ return true;
+ };
+ auto epsilon_to_zero = [](double d) -> double {
+ return std::abs(d) < std::numeric_limits<float>::epsilon() ? 0 : d;
+ };
+
+ // Compute X scale factor and normalize the first column.
+ if (!extract_scale(c0, decomp.scale[0]))
+ return absl::nullopt;
+
+ // Compute XY shear factor and make 2nd column orthogonal to 1st.
+ decomp.skew[0] = epsilon_to_zero(sum3(c0 * c1));
+ c1 -= c0 * decomp.skew[0];
+
+ // Now, compute Y scale and normalize 2nd column.
+ if (!extract_scale(c1, decomp.scale[1]))
+ return absl::nullopt;
+
+ decomp.skew[0] /= decomp.scale[1];
+
+ // Compute XZ and YZ shears, and orthogonalize the 3rd column.
+ decomp.skew[1] = epsilon_to_zero(sum3(c0 * c2));
+ c2 -= c0 * decomp.skew[1];
+ decomp.skew[2] = epsilon_to_zero(sum3(c1 * c2));
+ c2 -= c1 * decomp.skew[2];
+
+ // Next, get Z scale and normalize the 3rd column.
+ if (!extract_scale(c2, decomp.scale[2]))
+ return absl::nullopt;
+
+ decomp.skew[1] /= decomp.scale[2];
+ decomp.skew[2] /= decomp.scale[2];
+
+ // At this point, the matrix is orthonormal.
+ // Check for a coordinate system flip. If the determinant is -1, then negate
+ // the matrix and the scaling factors.
+ auto cross3 = [](Double4 a, Double4 b) -> Double4 {
+ return Double4{a[1], a[2], a[0], a[3]} * Double4{b[2], b[0], b[1], b[3]} -
+ Double4{a[2], a[0], a[1], a[3]} * Double4{b[1], b[2], b[0], b[3]};
+ };
+ Double4 pdum3 = cross3(c1, c2);
+ if (sum3(c0 * pdum3) < 0) {
+ // Flip all 3 scaling factors, following the 3d decomposition spec. See
+ // documentation of Transform::Decompose() about the difference between
+ // the 2d spec and and 3d spec about scale flipping.
+ decomp.scale[0] *= -1;
+ decomp.scale[1] *= -1;
+ decomp.scale[2] *= -1;
+ c0 *= -1;
+ c1 *= -1;
+ c2 *= -1;
+ }
+
+ // Lastly, compute the quaternions.
+ // See https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion.
+ // Note: deviating from spec (http://www.w3.org/TR/css3-transforms/)
+ // which has a degenerate case when the trace (t) of the orthonormal matrix
+ // (Q) approaches -1. In the Wikipedia article, Q_ij is indexing on row then
+ // column. Thus, Q_ij = column[j][i].
+
+ // The following are equivalent representations of the rotation matrix:
+ //
+ // Axis-angle form:
+ //
+ // [ c+(1-c)x^2 (1-c)xy-sz (1-c)xz+sy ] c = cos theta
+ // R = [ (1-c)xy+sz c+(1-c)y^2 (1-c)yz-sx ] s = sin theta
+ // [ (1-c)xz-sy (1-c)yz+sx c+(1-c)z^2 ] [x,y,z] = axis or rotation
+ //
+ // The sum of the diagonal elements (trace) is a simple function of the cosine
+ // of the angle. The w component of the quaternion is cos(theta/2), and we
+ // make use of the double angle formula to directly compute w from the
+ // trace. Differences between pairs of skew symmetric elements in this matrix
+ // isolate the remaining components. Since w can be zero (also numerically
+ // unstable if near zero), we cannot rely solely on this approach to compute
+ // the quaternion components.
+ //
+ // Quaternion form:
+ //
+ // [ 1-2(y^2+z^2) 2(xy-zw) 2(xz+yw) ]
+ // r = [ 2(xy+zw) 1-2(x^2+z^2) 2(yz-xw) ] q = (x,y,z,w)
+ // [ 2(xz-yw) 2(yz+xw) 1-2(x^2+y^2) ]
+ //
+ // Different linear combinations of the diagonal elements isolates x, y or z.
+ // Sums or differences between skew symmetric elements isolate the remainder.
+
+ double r, s, t, x, y, z, w;
+
+ t = c0[0] + c1[1] + c2[2]; // trace of Q
+
+ // https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion
+ if (1 + t > 0.001) {
+ // Numerically stable as long as 1+t is not close to zero. Otherwise use the
+ // diagonal element with the greatest value to compute the quaternions.
+ r = std::sqrt(1.0 + t);
+ s = 0.5 / r;
+ w = 0.5 * r;
+ x = (c1[2] - c2[1]) * s;
+ y = (c2[0] - c0[2]) * s;
+ z = (c0[1] - c1[0]) * s;
+ } else if (c0[0] > c1[1] && c0[0] > c2[2]) {
+ // Q_xx is largest.
+ r = std::sqrt(1.0 + c0[0] - c1[1] - c2[2]);
+ s = 0.5 / r;
+ x = 0.5 * r;
+ y = (c1[0] + c0[1]) * s;
+ z = (c2[0] + c0[2]) * s;
+ w = (c1[2] - c2[1]) * s;
+ } else if (c1[1] > c2[2]) {
+ // Q_yy is largest.
+ r = std::sqrt(1.0 - c0[0] + c1[1] - c2[2]);
+ s = 0.5 / r;
+ x = (c1[0] + c0[1]) * s;
+ y = 0.5 * r;
+ z = (c2[1] + c1[2]) * s;
+ w = (c2[0] - c0[2]) * s;
+ } else {
+ // Q_zz is largest.
+ r = std::sqrt(1.0 - c0[0] - c1[1] + c2[2]);
+ s = 0.5 / r;
+ x = (c2[0] + c0[2]) * s;
+ y = (c2[1] + c1[2]) * s;
+ z = 0.5 * r;
+ w = (c0[1] - c1[0]) * s;
+ }
+
+ decomp.quaternion.set_x(x);
+ decomp.quaternion.set_y(y);
+ decomp.quaternion.set_z(z);
+ decomp.quaternion.set_w(w);
+
+ return decomp;
+}
+
+} // namespace gfx
diff --git a/ui/gfx/geometry/matrix44.h b/ui/gfx/geometry/matrix44.h
new file mode 100644
index 0000000..cc3cb7c
--- /dev/null
+++ b/ui/gfx/geometry/matrix44.h
@@ -0,0 +1,203 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_MATRIX44_H_
+#define UI_GFX_GEOMETRY_MATRIX44_H_
+
+#include "base/check_op.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/geometry/double4.h"
+#include "ui/gfx/geometry/geometry_skia_export.h"
+
+namespace gfx {
+
+struct DecomposedTransform;
+
+// This is the underlying data structure of Transform. Don't use this type
+// directly.
+//
+// Throughout this class, we will be speaking in column vector convention.
+// i.e. Applying a transform T to vector V is T * V.
+// The components of the matrix and the vector look like:
+// \ col
+// r \ 0 1 2 3
+// o 0 | scale_x skew_xy skew_xz trans_x | | x |
+// w 1 | skew_yx scale_y skew_yz trans_y | * | y |
+// 2 | skew_zx skew_zy scale_z trans_z | | z |
+// 3 | persp_x persp_y persp_z persp_w | | w |
+//
+// Note that the names are just for remembering and don't have the exact
+// meanings when other components exist.
+//
+// The components correspond to the DOMMatrix mij (i,j = 1..4) components:
+// i = col + 1
+// j = row + 1
+class GEOMETRY_SKIA_EXPORT Matrix44 {
+ public:
+ enum UninitializedTag { kUninitialized };
+
+ explicit Matrix44(UninitializedTag) {}
+
+ constexpr Matrix44()
+ : matrix_{{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}, {0, 0, 0, 1}} {}
+
+ // The parameters are in col-major order.
+ // clang-format off
+ constexpr Matrix44(double r0c0, double r1c0, double r2c0, double r3c0,
+ double r0c1, double r1c1, double r2c1, double r3c1,
+ double r0c2, double r1c2, double r2c2, double r3c2,
+ double r0c3, double r1c3, double r2c3, double r3c3)
+ // matrix_ is indexed by [col][row] (i.e. col-major).
+ : matrix_{{r0c0, r1c0, r2c0, r3c0},
+ {r0c1, r1c1, r2c1, r3c1},
+ {r0c2, r1c2, r2c2, r3c2},
+ {r0c3, r1c3, r2c3, r3c3}} {}
+ // clang-format on
+
+ bool operator==(const Matrix44& other) const {
+ return AllTrue(Col(0) == other.Col(0)) && AllTrue(Col(1) == other.Col(1)) &&
+ AllTrue(Col(2) == other.Col(2)) && AllTrue(Col(3) == other.Col(3));
+ }
+ bool operator!=(const Matrix44& other) const { return !(other == *this); }
+
+ // Returns true if the matrix is identity.
+ bool IsIdentity() const { return *this == Matrix44(); }
+
+ // Returns true if the matrix contains translate or is identity.
+ bool IsIdentityOrTranslation() const {
+ return AllTrue(Col(0) == Double4{1, 0, 0, 0}) &&
+ AllTrue(Col(1) == Double4{0, 1, 0, 0}) &&
+ AllTrue(Col(2) == Double4{0, 0, 1, 0}) && matrix_[3][3] == 1;
+ }
+
+ // Returns true if the matrix only contains scale or translate or is identity.
+ bool IsScaleOrTranslation() const {
+ return AllTrue(Double4{matrix_[0][1], matrix_[0][2], matrix_[0][3],
+ matrix_[1][0]} == Double4{0, 0, 0, 0}) &&
+ AllTrue(Double4{matrix_[1][2], matrix_[1][3], matrix_[2][0],
+ matrix_[2][1]} == Double4{0, 0, 0, 0}) &&
+ matrix_[2][3] == 0 && matrix_[3][3] == 1;
+ }
+
+ // Returns true if the matrix only contains scale or is identity.
+ bool IsScale() const {
+ return IsScaleOrTranslation() && AllTrue(Col(3) == Double4{0, 0, 0, 1});
+ }
+
+ bool IsFlat() const {
+ return AllTrue(Col(2) == Double4{0, 0, 1, 0}) &&
+ AllTrue(Double4{matrix_[0][2], matrix_[1][2], 0, matrix_[3][2]} ==
+ Double4{0, 0, 0, 0});
+ }
+
+ bool HasPerspective() const {
+ return !AllTrue(Double4{matrix_[0][3], matrix_[1][3], matrix_[2][3],
+ matrix_[3][3]} == Double4{0, 0, 0, 1});
+ }
+
+ bool Is2dTransform() const { return IsFlat() && !HasPerspective(); }
+
+ // Gets a value at |row|, |col| from the matrix.
+ constexpr double rc(int row, int col) const {
+ DCHECK_LE(static_cast<unsigned>(row), 3u);
+ DCHECK_LE(static_cast<unsigned>(col), 3u);
+ return matrix_[col][row];
+ }
+
+ // Set a value in the matrix at |row|, |col|.
+ void set_rc(int row, int col, double value) {
+ DCHECK_LE(static_cast<unsigned>(row), 3u);
+ DCHECK_LE(static_cast<unsigned>(col), 3u);
+ matrix_[col][row] = value;
+ }
+
+ void GetColMajor(double[16]) const;
+ void GetColMajorF(float[16]) const;
+
+ // this = this * translation.
+ void PreTranslate(double dx, double dy);
+ void PreTranslate3d(double dx, double dy, double dz);
+ // this = translation * this.
+ void PostTranslate(double dx, double dy);
+ void PostTranslate3d(double dx, double dy, double dz);
+
+ // this = this * scale.
+ void PreScale(double sx, double sy);
+ void PreScale3d(double sx, double sy, double sz);
+ // this = scale * this.
+ void PostScale(double sx, double sy);
+ void PostScale3d(double sx, double sy, double sz);
+
+ // Rotates this matrix about the specified unit-length axis vector,
+ // by an angle specified by its sin() and cos(). This does not attempt to
+ // verify that axis(x, y, z).length() == 1 or that the sin, cos values are
+ // correct. this = this * rotation.
+ void RotateUnitSinCos(double x,
+ double y,
+ double z,
+ double sin_angle,
+ double cos_angle);
+
+ // Special case for x, y or z axis of the above function.
+ void RotateAboutXAxisSinCos(double sin_angle, double cos_angle);
+ void RotateAboutYAxisSinCos(double sin_angle, double cos_angle);
+ void RotateAboutZAxisSinCos(double sin_angle, double cos_angle);
+
+ // this = this * skew.
+ void Skew(double tan_skew_x, double tan_skew_y);
+
+ // |1 skew[0] skew[1] 0|
+ // this = this * |0 1 skew[2] 0|
+ // |0 0 1 0|
+ // |0 0 0 1|
+ void ApplyDecomposedSkews(const double skews[3]);
+
+ // this = this * perspective.
+ void ApplyPerspectiveDepth(double perspective);
+
+ // this = this * m.
+ void PreConcat(const Matrix44& m) { SetConcat(*this, m); }
+ // this = m * this.
+ void PostConcat(const Matrix44& m) { SetConcat(m, *this); }
+ // this = a * b.
+ void SetConcat(const Matrix44& a, const Matrix44& b);
+
+ // Returns true and set |inverse| to the inverted matrix if this matrix
+ // is invertible. Otherwise return false and leave the |inverse| parameter
+ // unchanged.
+ bool GetInverse(Matrix44& inverse) const;
+
+ bool IsInvertible() const;
+ double Determinant() const;
+
+ // Transposes this matrix in place.
+ void Transpose();
+
+ // See Transform::Zoom().
+ void Zoom(double zoom_factor);
+
+ // Applies the matrix to the vector in place.
+ void MapVector4(double vec[4]) const;
+
+ // Same as above, but assumes the vec[2] is 0 and vec[3] is 1, discards
+ // vec[2], and returns vec[3].
+ double MapVector2(double vec[2]) const;
+
+ void Flatten();
+
+ absl::optional<DecomposedTransform> Decompose() const;
+
+ private:
+ absl::optional<DecomposedTransform> Decompose2d() const;
+
+ ALWAYS_INLINE Double4 Col(int i) const { return LoadDouble4(matrix_[i]); }
+ ALWAYS_INLINE void SetCol(int i, Double4 v) { StoreDouble4(v, matrix_[i]); }
+
+ // This is indexed by [col][row].
+ double matrix_[4][4];
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_MATRIX44_H_
diff --git a/ui/gfx/geometry/mojom/BUILD.gn b/ui/gfx/geometry/mojom/BUILD.gn
index a5f18d7..aa57e72 100644
--- a/ui/gfx/geometry/mojom/BUILD.gn
+++ b/ui/gfx/geometry/mojom/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
+# Copyright 2016 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -51,6 +51,10 @@
cpp = "::gfx::InsetsF"
},
{
+ mojom = "gfx.mojom.QuadF"
+ cpp = "::gfx::QuadF"
+ },
+ {
mojom = "gfx.mojom.Quaternion"
cpp = "::gfx::Quaternion"
},
diff --git a/ui/gfx/geometry/mojom/geometry.mojom b/ui/gfx/geometry/mojom/geometry.mojom
index 30be3e6..b23d929 100644
--- a/ui/gfx/geometry/mojom/geometry.mojom
+++ b/ui/gfx/geometry/mojom/geometry.mojom
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -86,3 +86,10 @@
double z;
double w;
};
+
+struct QuadF {
+ PointF p1;
+ PointF p2;
+ PointF p3;
+ PointF p4;
+};
diff --git a/ui/gfx/geometry/mojom/geometry_mojom_traits.h b/ui/gfx/geometry/mojom/geometry_mojom_traits.h
index aa48273..f169c87 100644
--- a/ui/gfx/geometry/mojom/geometry_mojom_traits.h
+++ b/ui/gfx/geometry/mojom/geometry_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,6 +11,7 @@
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point3_f.h"
#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/quad_f.h"
#include "ui/gfx/geometry/quaternion.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
@@ -29,7 +30,8 @@
static int bottom(const gfx::Insets& p) { return p.bottom(); }
static int right(const gfx::Insets& p) { return p.right(); }
static bool Read(gfx::mojom::InsetsDataView data, gfx::Insets* out) {
- out->Set(data.top(), data.left(), data.bottom(), data.right());
+ *out =
+ gfx::Insets::TLBR(data.top(), data.left(), data.bottom(), data.right());
return true;
}
};
@@ -41,7 +43,8 @@
static float bottom(const gfx::InsetsF& p) { return p.bottom(); }
static float right(const gfx::InsetsF& p) { return p.right(); }
static bool Read(gfx::mojom::InsetsFDataView data, gfx::InsetsF* out) {
- out->Set(data.top(), data.left(), data.bottom(), data.right());
+ *out = gfx::InsetsF::TLBR(data.top(), data.left(), data.bottom(),
+ data.right());
return true;
}
};
@@ -183,6 +186,37 @@
}
};
+template <>
+struct StructTraits<gfx::mojom::QuadFDataView, gfx::QuadF> {
+ static gfx::PointF p1(const gfx::QuadF& q) { return q.p1(); }
+ static gfx::PointF p2(const gfx::QuadF& q) { return q.p2(); }
+ static gfx::PointF p3(const gfx::QuadF& q) { return q.p3(); }
+ static gfx::PointF p4(const gfx::QuadF& q) { return q.p4(); }
+ static bool Read(gfx::mojom::QuadFDataView data, gfx::QuadF* out) {
+ gfx::PointF p1;
+ if (!data.ReadP1(&p1)) {
+ return false;
+ }
+ out->set_p1(p1);
+ gfx::PointF p2;
+ if (!data.ReadP2(&p2)) {
+ return false;
+ }
+ out->set_p2(p2);
+ gfx::PointF p3;
+ if (!data.ReadP3(&p3)) {
+ return false;
+ }
+ out->set_p3(p3);
+ gfx::PointF p4;
+ if (!data.ReadP4(&p4)) {
+ return false;
+ }
+ out->set_p4(p4);
+ return true;
+ }
+};
+
} // namespace mojo
#endif // UI_GFX_GEOMETRY_MOJOM_GEOMETRY_MOJOM_TRAITS_H_
diff --git a/ui/gfx/geometry/mojom/geometry_mojom_traits_unittest.cc b/ui/gfx/geometry/mojom/geometry_mojom_traits_unittest.cc
index d2c5959..c76430a 100644
--- a/ui/gfx/geometry/mojom/geometry_mojom_traits_unittest.cc
+++ b/ui/gfx/geometry/mojom/geometry_mojom_traits_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -88,6 +88,10 @@
std::move(callback).Run(q);
}
+ void EchoQuadF(const QuadF& q, EchoQuadFCallback callback) override {
+ std::move(callback).Run(q);
+ }
+
base::test::TaskEnvironment task_environment_;
mojo::ReceiverSet<GeometryTraitsTestService> traits_test_receivers_;
};
@@ -186,7 +190,7 @@
const int32_t left = 5678;
const int32_t bottom = 4321;
const int32_t right = 8765;
- gfx::Insets input(top, left, bottom, right);
+ auto input = gfx::Insets::TLBR(top, left, bottom, right);
mojo::Remote<mojom::GeometryTraitsTestService> remote = GetTraitsTestRemote();
gfx::Insets output;
remote->EchoInsets(input, &output);
@@ -201,7 +205,7 @@
const float left = 5678.2f;
const float bottom = 4321.3f;
const float right = 8765.4f;
- gfx::InsetsF input(top, left, bottom, right);
+ auto input = gfx::InsetsF::TLBR(top, left, bottom, right);
mojo::Remote<mojom::GeometryTraitsTestService> remote = GetTraitsTestRemote();
gfx::InsetsF output;
remote->EchoInsetsF(input, &output);
@@ -261,4 +265,20 @@
EXPECT_EQ(w, output.w());
}
+TEST_F(GeometryStructTraitsTest, QuadF) {
+ const PointF p1(1234.5, 6789.6);
+ const PointF p2(-31415.9, 27182.8);
+ const PointF p3(5432.1, -5678);
+ const PointF p4(-2468.0, -3579.1);
+ gfx::QuadF input(p1, p2, p3, p4);
+ mojo::Remote<mojom::GeometryTraitsTestService> remote = GetTraitsTestRemote();
+ gfx::QuadF output;
+ remote->EchoQuadF(input, &output);
+ EXPECT_EQ(p1, output.p1());
+ EXPECT_EQ(p2, output.p2());
+ EXPECT_EQ(p3, output.p3());
+ EXPECT_EQ(p4, output.p4());
+ EXPECT_EQ(input, output);
+}
+
} // namespace gfx
diff --git a/ui/gfx/geometry/mojom/geometry_traits_test_service.mojom b/ui/gfx/geometry/mojom/geometry_traits_test_service.mojom
index 97b69ad..472a807 100644
--- a/ui/gfx/geometry/mojom/geometry_traits_test_service.mojom
+++ b/ui/gfx/geometry/mojom/geometry_traits_test_service.mojom
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -47,4 +47,7 @@
[Sync]
EchoQuaternion(Quaternion q) => (Quaternion pass);
+
+ [Sync]
+ EchoQuadF(QuadF q) => (QuadF pass);
};
diff --git a/ui/gfx/geometry/outsets.h b/ui/gfx/geometry/outsets.h
new file mode 100644
index 0000000..a14635e
--- /dev/null
+++ b/ui/gfx/geometry/outsets.h
@@ -0,0 +1,46 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_OUTSETS_H_
+#define UI_GFX_GEOMETRY_OUTSETS_H_
+
+#include "base/numerics/clamped_math.h"
+#include "ui/gfx/geometry/geometry_export.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/insets_outsets_base.h"
+
+namespace gfx {
+
+// This can be used to represent a space surrounding a rectangle, by
+// "expanding" the rectangle by the outset amount on all four sides.
+class Outsets : public InsetsOutsetsBase<Outsets> {
+ public:
+ using InsetsOutsetsBase::InsetsOutsetsBase;
+
+ // Conversion from Outsets to Insets negates all components.
+ Insets ToInsets() const {
+ return Insets()
+ .set_left_right(-left(), -right())
+ .set_top_bottom(-top(), -bottom());
+ }
+};
+
+inline Outsets operator+(Outsets lhs, const Outsets& rhs) {
+ lhs += rhs;
+ return lhs;
+}
+
+inline Outsets operator-(Outsets lhs, const Outsets& rhs) {
+ lhs -= rhs;
+ return lhs;
+}
+
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const Outsets&, ::std::ostream* os);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_OUTSETS_H_
diff --git a/ui/gfx/geometry/outsets_f.h b/ui/gfx/geometry/outsets_f.h
new file mode 100644
index 0000000..19ba1bd
--- /dev/null
+++ b/ui/gfx/geometry/outsets_f.h
@@ -0,0 +1,46 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_OUTSETS_F_H_
+#define UI_GFX_GEOMETRY_OUTSETS_F_H_
+
+#include "ui/gfx/geometry/geometry_export.h"
+#include "ui/gfx/geometry/insets_f.h"
+#include "ui/gfx/geometry/insets_outsets_f_base.h"
+
+namespace gfx {
+
+// A floating point version of gfx::Outsets.
+class GEOMETRY_EXPORT OutsetsF : public InsetsOutsetsFBase<OutsetsF> {
+ public:
+ using InsetsOutsetsFBase::InsetsOutsetsFBase;
+
+ // Conversion from OutsetsF to InsetsF negates all components.
+ InsetsF ToInsets() const {
+ return InsetsF()
+ .set_left(-left())
+ .set_right(-right())
+ .set_top(-top())
+ .set_bottom(-bottom());
+ }
+};
+
+inline OutsetsF operator+(OutsetsF lhs, const OutsetsF& rhs) {
+ lhs += rhs;
+ return lhs;
+}
+
+inline OutsetsF operator-(OutsetsF lhs, const OutsetsF& rhs) {
+ lhs -= rhs;
+ return lhs;
+}
+
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const OutsetsF&, ::std::ostream* os);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_OUTSETS_F_H_
diff --git a/ui/gfx/geometry/point.cc b/ui/gfx/geometry/point.cc
index f167f20..3988998 100644
--- a/ui/gfx/geometry/point.cc
+++ b/ui/gfx/geometry/point.cc
@@ -1,17 +1,105 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/point.h"
#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/point_f.h"
+
+#if BUILDFLAG(IS_WIN)
+#include <windows.h>
+#elif BUILDFLAG(IS_IOS)
+#include <CoreGraphics/CoreGraphics.h>
+#elif BUILDFLAG(IS_MAC)
+#include <ApplicationServices/ApplicationServices.h>
+#endif
namespace gfx {
-template class PointBase<Point, int, Vector2d>;
+#if BUILDFLAG(IS_WIN)
+Point::Point(DWORD point) {
+ POINTS points = MAKEPOINTS(point);
+ x_ = points.x;
+ y_ = points.y;
+}
+
+Point::Point(const POINT& point) : x_(point.x), y_(point.y) {
+}
+
+Point& Point::operator=(const POINT& point) {
+ x_ = point.x;
+ y_ = point.y;
+ return *this;
+}
+#elif BUILDFLAG(IS_APPLE)
+Point::Point(const CGPoint& point) : x_(point.x), y_(point.y) {
+}
+#endif
+
+#if BUILDFLAG(IS_WIN)
+POINT Point::ToPOINT() const {
+ POINT p;
+ p.x = x();
+ p.y = y();
+ return p;
+}
+#elif BUILDFLAG(IS_APPLE)
+CGPoint Point::ToCGPoint() const {
+ return CGPointMake(x(), y());
+}
+#endif
+
+void Point::SetToMin(const Point& other) {
+ x_ = std::min(x_, other.x_);
+ y_ = std::min(y_, other.y_);
+}
+
+void Point::SetToMax(const Point& other) {
+ x_ = std::max(x_, other.x_);
+ y_ = std::max(y_, other.y_);
+}
std::string Point::ToString() const {
return base::StringPrintf("%d,%d", x(), y());
}
+Point ScaleToCeiledPoint(const Point& point, float x_scale, float y_scale) {
+ if (x_scale == 1.f && y_scale == 1.f)
+ return point;
+ return ToCeiledPoint(ScalePoint(gfx::PointF(point), x_scale, y_scale));
+}
+
+Point ScaleToCeiledPoint(const Point& point, float scale) {
+ if (scale == 1.f)
+ return point;
+ return ToCeiledPoint(ScalePoint(gfx::PointF(point), scale, scale));
+}
+
+Point ScaleToFlooredPoint(const Point& point, float x_scale, float y_scale) {
+ if (x_scale == 1.f && y_scale == 1.f)
+ return point;
+ return ToFlooredPoint(ScalePoint(gfx::PointF(point), x_scale, y_scale));
+}
+
+Point ScaleToFlooredPoint(const Point& point, float scale) {
+ if (scale == 1.f)
+ return point;
+ return ToFlooredPoint(ScalePoint(gfx::PointF(point), scale, scale));
+}
+
+Point ScaleToRoundedPoint(const Point& point, float x_scale, float y_scale) {
+ if (x_scale == 1.f && y_scale == 1.f)
+ return point;
+ return ToRoundedPoint(ScalePoint(gfx::PointF(point), x_scale, y_scale));
+}
+
+Point ScaleToRoundedPoint(const Point& point, float scale) {
+ if (scale == 1.f)
+ return point;
+ return ToRoundedPoint(ScalePoint(gfx::PointF(point), scale, scale));
+}
+
} // namespace gfx
diff --git a/ui/gfx/geometry/point.h b/ui/gfx/geometry/point.h
index 3d02ccf..1477367 100644
--- a/ui/gfx/geometry/point.h
+++ b/ui/gfx/geometry/point.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,30 +7,100 @@
#include <iosfwd>
#include <string>
+#include <tuple>
-#include "ui/gfx/geometry/point_base.h"
-#include "ui/gfx/geometry/point_f.h"
+#include "base/numerics/clamped_math.h"
+#include "build/build_config.h"
+#include "ui/gfx/geometry/geometry_export.h"
#include "ui/gfx/geometry/vector2d.h"
+#if BUILDFLAG(IS_WIN)
+typedef unsigned long DWORD;
+typedef struct tagPOINT POINT;
+#elif BUILDFLAG(IS_APPLE)
+typedef struct CGPoint CGPoint;
+#endif
+
namespace gfx {
// A point has an x and y coordinate.
-class Point : public PointBase<Point, int, Vector2d> {
+class GEOMETRY_EXPORT Point {
public:
- Point() : PointBase<Point, int, Vector2d>(0, 0) {}
- Point(int x, int y) : PointBase<Point, int, Vector2d>(x, y) {}
+ constexpr Point() : x_(0), y_(0) {}
+ constexpr Point(int x, int y) : x_(x), y_(y) {}
+#if BUILDFLAG(IS_WIN)
+ // |point| is a DWORD value that contains a coordinate. The x-coordinate is
+ // the low-order short and the y-coordinate is the high-order short. This
+ // value is commonly acquired from GetMessagePos/GetCursorPos.
+ explicit Point(DWORD point);
+ explicit Point(const POINT& point);
+ Point& operator=(const POINT& point);
+#elif BUILDFLAG(IS_APPLE)
+ explicit Point(const CGPoint& point);
+#endif
- ~Point() {}
+#if BUILDFLAG(IS_WIN)
+ POINT ToPOINT() const;
+#elif BUILDFLAG(IS_APPLE)
+ CGPoint ToCGPoint() const;
+#endif
- operator PointF() const {
- return PointF(static_cast<float>(x()), static_cast<float>(y()));
+ constexpr int x() const { return x_; }
+ constexpr int y() const { return y_; }
+ void set_x(int x) { x_ = x; }
+ void set_y(int y) { y_ = y; }
+
+ void SetPoint(int x, int y) {
+ x_ = x;
+ y_ = y;
+ }
+
+ void Offset(int delta_x, int delta_y) {
+ x_ = base::ClampAdd(x_, delta_x);
+ y_ = base::ClampAdd(y_, delta_y);
+ }
+
+ void operator+=(const Vector2d& vector) {
+ x_ = base::ClampAdd(x_, vector.x());
+ y_ = base::ClampAdd(y_, vector.y());
+ }
+
+ void operator-=(const Vector2d& vector) {
+ x_ = base::ClampSub(x_, vector.x());
+ y_ = base::ClampSub(y_, vector.y());
+ }
+
+ void SetToMin(const Point& other);
+ void SetToMax(const Point& other);
+
+ bool IsOrigin() const { return x_ == 0 && y_ == 0; }
+
+ Vector2d OffsetFromOrigin() const { return Vector2d(x_, y_); }
+
+ void Transpose() {
+ using std::swap;
+ swap(x_, y_);
+ }
+
+ // A point is less than another point if its y-value is closer
+ // to the origin. If the y-values are the same, then point with
+ // the x-value closer to the origin is considered less than the
+ // other.
+ // This comparison is required to use Point in sets, or sorted
+ // vectors.
+ bool operator<(const Point& rhs) const {
+ return std::tie(y_, x_) < std::tie(rhs.y_, rhs.x_);
}
// Returns a string representation of point.
std::string ToString() const;
+
+ private:
+ int x_;
+ int y_;
};
-inline bool operator==(const Point& lhs, const Point& rhs) {
+constexpr bool operator==(const Point& lhs, const Point& rhs) {
return lhs.x() == rhs.x() && lhs.y() == rhs.y();
}
@@ -51,14 +121,36 @@
}
inline Vector2d operator-(const Point& lhs, const Point& rhs) {
- return Vector2d(lhs.x() - rhs.x(), lhs.y() - rhs.y());
+ return Vector2d(base::ClampSub(lhs.x(), rhs.x()),
+ base::ClampSub(lhs.y(), rhs.y()));
}
inline Point PointAtOffsetFromOrigin(const Vector2d& offset_from_origin) {
return Point(offset_from_origin.x(), offset_from_origin.y());
}
-extern template class PointBase<Point, int, Vector2d>;
+inline Point TransposePoint(const gfx::Point& p) {
+ return Point(p.y(), p.x());
+}
+
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const Point& point, ::std::ostream* os);
+
+// Helper methods to scale a gfx::Point to a new gfx::Point.
+GEOMETRY_EXPORT Point ScaleToCeiledPoint(const Point& point,
+ float x_scale,
+ float y_scale);
+GEOMETRY_EXPORT Point ScaleToCeiledPoint(const Point& point, float x_scale);
+GEOMETRY_EXPORT Point ScaleToFlooredPoint(const Point& point,
+ float x_scale,
+ float y_scale);
+GEOMETRY_EXPORT Point ScaleToFlooredPoint(const Point& point, float x_scale);
+GEOMETRY_EXPORT Point ScaleToRoundedPoint(const Point& point,
+ float x_scale,
+ float y_scale);
+GEOMETRY_EXPORT Point ScaleToRoundedPoint(const Point& point, float x_scale);
} // namespace gfx
diff --git a/ui/gfx/geometry/point3_f.cc b/ui/gfx/geometry/point3_f.cc
index 465376e..f30bfa3 100644
--- a/ui/gfx/geometry/point3_f.cc
+++ b/ui/gfx/geometry/point3_f.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,7 +9,7 @@
namespace gfx {
std::string Point3F::ToString() const {
- return base::StringPrintf("%f,%f,%f", x_, y_, z_);
+ return base::StringPrintf("%g,%g,%g", x_, y_, z_);
}
Point3F operator+(const Point3F& lhs, const Vector3dF& rhs) {
diff --git a/ui/gfx/geometry/point3_f.h b/ui/gfx/geometry/point3_f.h
index 07b95c0..ba46fb5 100644
--- a/ui/gfx/geometry/point3_f.h
+++ b/ui/gfx/geometry/point3_f.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,30 +8,32 @@
#include <iosfwd>
#include <string>
+#include "ui/gfx/geometry/geometry_export.h"
#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/vector3d_f.h"
namespace gfx {
// A point has an x, y and z coordinate.
-class Point3F {
+class GEOMETRY_EXPORT Point3F {
public:
- Point3F() : x_(0), y_(0), z_(0) {}
+ constexpr Point3F() : x_(0), y_(0), z_(0) {}
+ constexpr Point3F(float x, float y, float z) : x_(x), y_(y), z_(z) {}
- Point3F(float x, float y, float z) : x_(x), y_(y), z_(z) {}
+ constexpr explicit Point3F(const PointF& point)
+ : x_(point.x()), y_(point.y()), z_(0) {}
- explicit Point3F(const PointF& point) : x_(point.x()), y_(point.y()), z_(0) {}
-
- ~Point3F() {}
-
- void Scale(float scale) { Scale(scale, scale, scale); }
+ void Scale(float scale) {
+ Scale(scale, scale, scale);
+ }
void Scale(float x_scale, float y_scale, float z_scale) {
SetPoint(x() * x_scale, y() * y_scale, z() * z_scale);
}
- float x() const { return x_; }
- float y() const { return y_; }
- float z() const { return z_; }
+ constexpr float x() const { return x_; }
+ constexpr float y() const { return y_; }
+ constexpr float z() const { return z_; }
void set_x(float x) { x_ = x; }
void set_y(float y) { y_ = y; }
@@ -43,6 +45,22 @@
z_ = z;
}
+ bool IsOrigin() const { return x_ == 0 && y_ == 0 && z_ == 0; }
+
+ // Offset the point by the given vector.
+ void operator+=(const Vector3dF& v) {
+ x_ += v.x();
+ y_ += v.y();
+ z_ += v.z();
+ }
+
+ // Offset the point by the given vector's inverse.
+ void operator-=(const Vector3dF& v) {
+ x_ -= v.x();
+ y_ -= v.y();
+ z_ -= v.z();
+ }
+
// Returns the squared euclidean distance between two points.
float SquaredDistanceTo(const Point3F& other) const {
float dx = x_ - other.x_;
@@ -53,6 +71,8 @@
PointF AsPointF() const { return PointF(x_, y_); }
+ Vector3dF OffsetFromOrigin() const { return Vector3dF(x_, y_, z_); }
+
// Returns a string representation of 3d point.
std::string ToString() const;
@@ -72,15 +92,41 @@
return !(lhs == rhs);
}
-inline Point3F ScalePoint(const Point3F& p, float x_scale, float y_scale,
+// Add a vector to a point, producing a new point offset by the vector.
+GEOMETRY_EXPORT Point3F operator+(const Point3F& lhs, const Vector3dF& rhs);
+
+// Subtract a vector from a point, producing a new point offset by the vector's
+// inverse.
+GEOMETRY_EXPORT Point3F operator-(const Point3F& lhs, const Vector3dF& rhs);
+
+// Subtract one point from another, producing a vector that represents the
+// distances between the two points along each axis.
+GEOMETRY_EXPORT Vector3dF operator-(const Point3F& lhs, const Point3F& rhs);
+
+inline Point3F PointAtOffsetFromOrigin(const Vector3dF& offset) {
+ return Point3F(offset.x(), offset.y(), offset.z());
+}
+
+inline Point3F ScalePoint(const Point3F& p,
+ float x_scale,
+ float y_scale,
float z_scale) {
return Point3F(p.x() * x_scale, p.y() * y_scale, p.z() * z_scale);
}
+inline Point3F ScalePoint(const Point3F& p, const Vector3dF& v) {
+ return Point3F(p.x() * v.x(), p.y() * v.y(), p.z() * v.z());
+}
+
inline Point3F ScalePoint(const Point3F& p, float scale) {
return ScalePoint(p, scale, scale, scale);
}
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const Point3F& point, ::std::ostream* os);
+
} // namespace gfx
#endif // UI_GFX_GEOMETRY_POINT3_F_H_
diff --git a/ui/gfx/geometry/point3_unittest.cc b/ui/gfx/geometry/point3_f_unittest.cc
similarity index 69%
rename from ui/gfx/geometry/point3_unittest.cc
rename to ui/gfx/geometry/point3_f_unittest.cc
index e1926ef..b656052 100644
--- a/ui/gfx/geometry/point3_unittest.cc
+++ b/ui/gfx/geometry/point3_f_unittest.cc
@@ -1,16 +1,16 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/gfx/geometry/point3_f.h"
+
#include <stddef.h>
-#include "base/cxx17_backports.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/point3_f.h"
namespace gfx {
-TEST(Point3Test, VectorArithmetic) {
+TEST(Point3FTest, VectorArithmetic) {
gfx::Point3F a(1.6f, 5.1f, 3.2f);
gfx::Vector3dF v1(3.1f, -3.2f, 9.3f);
gfx::Vector3dF v2(-8.1f, 1.2f, 3.3f);
@@ -28,7 +28,7 @@
{ gfx::Point3F(-9.6f, 9.5f, -2.8f), a - v1 + v2 }
};
- for (size_t i = 0; i < base::size(tests); ++i)
+ for (size_t i = 0; i < std::size(tests); ++i)
EXPECT_EQ(tests[i].expected.ToString(),
tests[i].actual.ToString());
@@ -39,7 +39,7 @@
EXPECT_EQ(Point3F(12.8f, 0.7f, 9.2f).ToString(), a.ToString());
}
-TEST(Point3Test, VectorFromPoints) {
+TEST(Point3FTest, VectorFromPoints) {
gfx::Point3F a(1.6f, 5.2f, 3.2f);
gfx::Vector3dF v1(3.1f, -3.2f, 9.3f);
@@ -47,7 +47,7 @@
EXPECT_EQ((b - a).ToString(), v1.ToString());
}
-TEST(Point3Test, Scale) {
+TEST(Point3FTest, Scale) {
EXPECT_EQ(Point3F().ToString(), ScalePoint(Point3F(), 2.f).ToString());
EXPECT_EQ(Point3F().ToString(),
ScalePoint(Point3F(), 2.f, 2.f, 2.f).ToString());
@@ -68,4 +68,23 @@
EXPECT_EQ(Point3F(12.f, -6.f, 6.f).ToString(), point.ToString());
}
+TEST(Point3FTest, IsOrigin) {
+ EXPECT_TRUE(Point3F().IsOrigin());
+ EXPECT_FALSE(Point3F(0, 0, 0.1f).IsOrigin());
+ EXPECT_FALSE(Point3F(0, 0.1f, 0).IsOrigin());
+ EXPECT_FALSE(Point3F(0.1f, 0, 0).IsOrigin());
+ EXPECT_FALSE(Point3F(0, 0, -0.1f).IsOrigin());
+ EXPECT_FALSE(Point3F(0, -0.1f, 0).IsOrigin());
+ EXPECT_FALSE(Point3F(-0.1f, 0, 0).IsOrigin());
+}
+
+TEST(Point3FTest, OffsetFromOrigin) {
+ EXPECT_EQ(Vector3dF(1.25f, 2.5f, -3.75f),
+ Point3F(1.25f, 2.5f, -3.75f).OffsetFromOrigin());
+}
+
+TEST(Point3FTest, ToString) {
+ EXPECT_EQ("1.03125,2.5,-3", Point3F(1.03125, 2.5, -3).ToString());
+}
+
} // namespace gfx
diff --git a/ui/gfx/geometry/point_base.h b/ui/gfx/geometry/point_base.h
deleted file mode 100644
index 43eea50..0000000
--- a/ui/gfx/geometry/point_base.h
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_GEOMETRY_POINT_BASE_H_
-#define UI_GFX_GEOMETRY_POINT_BASE_H_
-
-#include <string>
-
-namespace gfx {
-
-// A point has an x and y coordinate.
-template <typename Class, typename Type, typename VectorClass>
-class PointBase {
- public:
- Type x() const { return x_; }
- Type y() const { return y_; }
-
- void SetPoint(Type x, Type y) {
- x_ = x;
- y_ = y;
- }
-
- void set_x(Type x) { x_ = x; }
- void set_y(Type y) { y_ = y; }
-
- void Offset(Type delta_x, Type delta_y) {
- x_ += delta_x;
- y_ += delta_y;
- }
-
- void operator+=(const VectorClass& vector) {
- x_ += vector.x();
- y_ += vector.y();
- }
-
- void operator-=(const VectorClass& vector) {
- x_ -= vector.x();
- y_ -= vector.y();
- }
-
- void SetToMin(const Class& other) {
- x_ = x_ <= other.x_ ? x_ : other.x_;
- y_ = y_ <= other.y_ ? y_ : other.y_;
- }
-
- void SetToMax(const Class& other) {
- x_ = x_ >= other.x_ ? x_ : other.x_;
- y_ = y_ >= other.y_ ? y_ : other.y_;
- }
-
- bool IsOrigin() const { return x_ == Type(0) && y_ == Type(0); }
-
- VectorClass OffsetFromOrigin() const { return VectorClass(x_, y_); }
-
- // A point is less than another point if its y-value is closer
- // to the origin. If the y-values are the same, then point with
- // the x-value closer to the origin is considered less than the
- // other.
- // This comparison is required to use Point in sets, or sorted
- // vectors.
- bool operator<(const Class& rhs) const {
- return (y_ == rhs.y_) ? (x_ < rhs.x_) : (y_ < rhs.y_);
- }
-
- protected:
- PointBase() {}
- PointBase(Type x, Type y) : x_(x), y_(y) {}
- // Destructor is intentionally made non virtual and protected.
- // Do not make this public.
- ~PointBase() {}
-
- private:
- Type x_;
- Type y_;
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_GEOMETRY_POINT_BASE_H_
diff --git a/ui/gfx/geometry/point_conversions.cc b/ui/gfx/geometry/point_conversions.cc
index bf800da..378f542 100644
--- a/ui/gfx/geometry/point_conversions.cc
+++ b/ui/gfx/geometry/point_conversions.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/point_conversions.h b/ui/gfx/geometry/point_conversions.h
index 894272c..2d94b52 100644
--- a/ui/gfx/geometry/point_conversions.h
+++ b/ui/gfx/geometry/point_conversions.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/point_f.cc b/ui/gfx/geometry/point_f.cc
index 4808ab7..06d49f2 100644
--- a/ui/gfx/geometry/point_f.cc
+++ b/ui/gfx/geometry/point_f.cc
@@ -1,23 +1,69 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/point_f.h"
+#include <cmath>
+
+#include "base/check.h"
#include "base/strings/stringprintf.h"
+#if !defined(STARBOARD)
+#include "base/trace_event/typed_macros.h"
+#endif // !defined(STARBOARD)
+#include "build/build_config.h"
+
+#if BUILDFLAG(IS_IOS)
+#include <CoreGraphics/CoreGraphics.h>
+#elif BUILDFLAG(IS_MAC)
+#include <ApplicationServices/ApplicationServices.h>
+#endif
namespace gfx {
-template class PointBase<PointF, float, Vector2dF>;
+#if BUILDFLAG(IS_APPLE)
+PointF::PointF(const CGPoint& p) : PointF(p.x, p.y) {}
+CGPoint PointF::ToCGPoint() const {
+ return CGPointMake(x(), y());
+}
+#endif
+
+void PointF::SetToMin(const PointF& other) {
+ x_ = std::min(x_, other.x_);
+ y_ = std::min(y_, other.y_);
+}
+
+void PointF::SetToMax(const PointF& other) {
+ x_ = std::max(x_, other.x_);
+ y_ = std::max(y_, other.y_);
+}
+
+bool PointF::IsWithinDistance(const PointF& rhs,
+ const float allowed_distance) const {
+ DCHECK(allowed_distance > 0);
+ float diff_x = x_ - rhs.x();
+ float diff_y = y_ - rhs.y();
+ float distance = std::sqrt(diff_x * diff_x + diff_y * diff_y);
+ return distance < allowed_distance;
+}
std::string PointF::ToString() const {
- return base::StringPrintf("%f,%f", x(), y());
+ return base::StringPrintf("%g,%g", x(), y());
}
+#if !defined(STARBOARD)
+void PointF::WriteIntoTrace(perfetto::TracedValue ctx) const {
+ perfetto::TracedDictionary dict = std::move(ctx).WriteDictionary();
+ dict.Add("x", x());
+ dict.Add("y", y());
+}
+#endif // !defined(STARBOARD)
+
PointF ScalePoint(const PointF& p, float x_scale, float y_scale) {
PointF scaled_p(p);
scaled_p.Scale(x_scale, y_scale);
return scaled_p;
}
+
} // namespace gfx
diff --git a/ui/gfx/geometry/point_f.h b/ui/gfx/geometry/point_f.h
index 6dd12ff..9397d48 100644
--- a/ui/gfx/geometry/point_f.h
+++ b/ui/gfx/geometry/point_f.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,44 +7,133 @@
#include <iosfwd>
#include <string>
+#include <tuple>
-#include "ui/gfx/geometry/point_base.h"
+#include "build/build_config.h"
+#include "ui/gfx/geometry/geometry_export.h"
+#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/vector2d_f.h"
+#if BUILDFLAG(IS_APPLE)
+struct CGPoint;
+#endif
+
+namespace perfetto {
+class TracedValue;
+}
namespace gfx {
-// A floating-point version of Point.
-class PointF : public PointBase<PointF, float, Vector2dF> {
+// A floating version of gfx::Point.
+class GEOMETRY_EXPORT PointF {
public:
- PointF() : PointBase<PointF, float, Vector2dF>(0, 0) {}
- PointF(float x, float y) : PointBase<PointF, float, Vector2dF>(x, y) {}
- ~PointF() {}
+ constexpr PointF() : x_(0.f), y_(0.f) {}
+ constexpr PointF(float x, float y) : x_(x), y_(y) {}
- void Scale(float scale) { Scale(scale, scale); }
+ constexpr explicit PointF(const Point& p)
+ : PointF(static_cast<float>(p.x()), static_cast<float>(p.y())) {}
+
+#if BUILDFLAG(IS_APPLE)
+ explicit PointF(const CGPoint&);
+ CGPoint ToCGPoint() const;
+#endif
+
+ constexpr float x() const { return x_; }
+ constexpr float y() const { return y_; }
+ void set_x(float x) { x_ = x; }
+ void set_y(float y) { y_ = y; }
+
+ void SetPoint(float x, float y) {
+ x_ = x;
+ y_ = y;
+ }
+
+ void Offset(float delta_x, float delta_y) {
+ x_ += delta_x;
+ y_ += delta_y;
+ }
+
+ constexpr void operator+=(const Vector2dF& vector) {
+ x_ += vector.x();
+ y_ += vector.y();
+ }
+
+ constexpr void operator-=(const Vector2dF& vector) {
+ x_ -= vector.x();
+ y_ -= vector.y();
+ }
+
+ void SetToMin(const PointF& other);
+ void SetToMax(const PointF& other);
+
+ bool IsOrigin() const { return x_ == 0 && y_ == 0; }
+
+ constexpr Vector2dF OffsetFromOrigin() const { return Vector2dF(x_, y_); }
+
+ // A point is less than another point if its y-value is closer
+ // to the origin. If the y-values are the same, then point with
+ // the x-value closer to the origin is considered less than the
+ // other.
+ // This comparison is required to use PointF in sets, or sorted
+ // vectors.
+ bool operator<(const PointF& rhs) const {
+ return std::tie(y_, x_) < std::tie(rhs.y_, rhs.x_);
+ }
+
+ void Scale(float scale) {
+ Scale(scale, scale);
+ }
void Scale(float x_scale, float y_scale) {
SetPoint(x() * x_scale, y() * y_scale);
}
+ // Scales the point by the inverse of the given scale.
+ void InvScale(float inv_scale) { InvScale(inv_scale, inv_scale); }
+
+ // Scales each component by the inverse of the given scales.
+ void InvScale(float inv_x_scale, float inv_y_scale) {
+ x_ /= inv_x_scale;
+ y_ /= inv_y_scale;
+ }
+
+ void Transpose() {
+ using std::swap;
+ swap(x_, y_);
+ }
+
+ // Uses the Pythagorean theorem to determine the straight line distance
+ // between the two points, and returns true if it is less than
+ // |allowed_distance|.
+ bool IsWithinDistance(const PointF& rhs, const float allowed_distance) const;
+
// Returns a string representation of point.
std::string ToString() const;
+
+#if !defined(STARBOARD)
+ // Write a represtation of this object into a trace event argument.
+ void WriteIntoTrace(perfetto::TracedValue) const;
+#endif // !defined(STARBOARD)
+
+ private:
+ float x_;
+ float y_;
};
-inline bool operator==(const PointF& lhs, const PointF& rhs) {
+constexpr bool operator==(const PointF& lhs, const PointF& rhs) {
return lhs.x() == rhs.x() && lhs.y() == rhs.y();
}
-inline bool operator!=(const PointF& lhs, const PointF& rhs) {
+constexpr bool operator!=(const PointF& lhs, const PointF& rhs) {
return !(lhs == rhs);
}
-inline PointF operator+(const PointF& lhs, const Vector2dF& rhs) {
+constexpr PointF operator+(const PointF& lhs, const Vector2dF& rhs) {
PointF result(lhs);
result += rhs;
return result;
}
-inline PointF operator-(const PointF& lhs, const Vector2dF& rhs) {
+constexpr PointF operator-(const PointF& lhs, const Vector2dF& rhs) {
PointF result(lhs);
result -= rhs;
return result;
@@ -58,13 +147,22 @@
return PointF(offset_from_origin.x(), offset_from_origin.y());
}
-PointF ScalePoint(const PointF& p, float x_scale, float y_scale);
+GEOMETRY_EXPORT PointF ScalePoint(const PointF& p,
+ float x_scale,
+ float y_scale);
inline PointF ScalePoint(const PointF& p, float scale) {
return ScalePoint(p, scale, scale);
}
-extern template class PointBase<PointF, float, Vector2dF>;
+inline PointF TransposePoint(const PointF& p) {
+ return PointF(p.y(), p.x());
+}
+
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const PointF& point, ::std::ostream* os);
} // namespace gfx
diff --git a/ui/gfx/geometry/point_f_unittest.cc b/ui/gfx/geometry/point_f_unittest.cc
new file mode 100644
index 0000000..50af47e
--- /dev/null
+++ b/ui/gfx/geometry/point_f_unittest.cc
@@ -0,0 +1,124 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/point_f.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_conversions.h"
+
+namespace gfx {
+
+TEST(PointFTest, PointToPointF) {
+ // Check that explicit conversion from integer to float compiles.
+ Point a(10, 20);
+ PointF b = PointF(a);
+
+ EXPECT_EQ(static_cast<float>(a.x()), b.x());
+ EXPECT_EQ(static_cast<float>(a.y()), b.y());
+}
+
+TEST(PointFTest, IsOrigin) {
+ EXPECT_FALSE(PointF(0.1f, 0).IsOrigin());
+ EXPECT_FALSE(PointF(0, 0.1f).IsOrigin());
+ EXPECT_FALSE(PointF(0.1f, 2).IsOrigin());
+ EXPECT_FALSE(PointF(-0.1f, 0).IsOrigin());
+ EXPECT_FALSE(PointF(0, -0.1f).IsOrigin());
+ EXPECT_FALSE(PointF(-0.1f, -2).IsOrigin());
+ EXPECT_TRUE(PointF(0, 0).IsOrigin());
+}
+
+TEST(PointFTest, ToRoundedPoint) {
+ EXPECT_EQ(Point(0, 0), ToRoundedPoint(PointF(0, 0)));
+ EXPECT_EQ(Point(0, 0), ToRoundedPoint(PointF(0.0001f, 0.0001f)));
+ EXPECT_EQ(Point(0, 0), ToRoundedPoint(PointF(0.4999f, 0.4999f)));
+ EXPECT_EQ(Point(1, 1), ToRoundedPoint(PointF(0.5f, 0.5f)));
+ EXPECT_EQ(Point(1, 1), ToRoundedPoint(PointF(0.9999f, 0.9999f)));
+
+ EXPECT_EQ(Point(10, 10), ToRoundedPoint(PointF(10, 10)));
+ EXPECT_EQ(Point(10, 10), ToRoundedPoint(PointF(10.0001f, 10.0001f)));
+ EXPECT_EQ(Point(10, 10), ToRoundedPoint(PointF(10.4999f, 10.4999f)));
+ EXPECT_EQ(Point(11, 11), ToRoundedPoint(PointF(10.5f, 10.5f)));
+ EXPECT_EQ(Point(11, 11), ToRoundedPoint(PointF(10.9999f, 10.9999f)));
+
+ EXPECT_EQ(Point(-10, -10), ToRoundedPoint(PointF(-10, -10)));
+ EXPECT_EQ(Point(-10, -10), ToRoundedPoint(PointF(-10.0001f, -10.0001f)));
+ EXPECT_EQ(Point(-10, -10), ToRoundedPoint(PointF(-10.4999f, -10.4999f)));
+ EXPECT_EQ(Point(-11, -11), ToRoundedPoint(PointF(-10.5f, -10.5f)));
+ EXPECT_EQ(Point(-11, -11), ToRoundedPoint(PointF(-10.9999f, -10.9999f)));
+}
+
+TEST(PointFTest, Scale) {
+ EXPECT_EQ(PointF(2, -2), ScalePoint(PointF(1, -1), 2));
+ EXPECT_EQ(PointF(2, -2), ScalePoint(PointF(1, -1), 2, 2));
+
+ PointF zero;
+ PointF one(1, -1);
+
+ zero.Scale(2);
+ zero.Scale(3, 1.5);
+
+ one.Scale(2);
+ one.Scale(3, 1.5);
+
+ EXPECT_EQ(PointF(), zero);
+ EXPECT_EQ(PointF(6, -3), one);
+}
+
+TEST(PointFTest, SetToMinMax) {
+ PointF a;
+
+ a = PointF(3.5f, 5.5f);
+ EXPECT_EQ(PointF(3.5f, 5.5f), a);
+ a.SetToMax(PointF(2.5f, 4.5f));
+ EXPECT_EQ(PointF(3.5f, 5.5f), a);
+ a.SetToMax(PointF(3.5f, 5.5f));
+ EXPECT_EQ(PointF(3.5f, 5.5f), a);
+ a.SetToMax(PointF(4.5f, 2.5f));
+ EXPECT_EQ(PointF(4.5f, 5.5f), a);
+ a.SetToMax(PointF(8.5f, 10.5f));
+ EXPECT_EQ(PointF(8.5f, 10.5f), a);
+
+ a.SetToMin(PointF(9.5f, 11.5f));
+ EXPECT_EQ(PointF(8.5f, 10.5f), a);
+ a.SetToMin(PointF(8.5f, 10.5f));
+ EXPECT_EQ(PointF(8.5f, 10.5f), a);
+ a.SetToMin(PointF(11.5f, 9.5f));
+ EXPECT_EQ(PointF(8.5f, 9.5f), a);
+ a.SetToMin(PointF(7.5f, 11.5f));
+ EXPECT_EQ(PointF(7.5f, 9.5f), a);
+ a.SetToMin(PointF(3.5f, 5.5f));
+ EXPECT_EQ(PointF(3.5f, 5.5f), a);
+}
+
+TEST(PointFTest, IsWithinDistance) {
+ PointF pt(10.f, 10.f);
+ EXPECT_TRUE(pt.IsWithinDistance(PointF(10.f, 10.f), 0.0000000000001f));
+ EXPECT_FALSE(pt.IsWithinDistance(PointF(8.f, 8.f), 1.f));
+
+ pt = PointF(-10.f, -10.f);
+ EXPECT_FALSE(
+ pt.IsWithinDistance(PointF(10.f, 10.f), /*allowed_distance=*/10.f));
+ EXPECT_TRUE(pt.IsWithinDistance(PointF(-9.9988f, -10.0013f), 0.0017689f));
+
+ pt = PointF(std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max());
+ EXPECT_FALSE(pt.IsWithinDistance(PointF(std::numeric_limits<float>::min(),
+ std::numeric_limits<float>::min()),
+ 100.f));
+}
+
+TEST(PointFTest, Transpose) {
+ gfx::PointF p(-1.5f, 2.5f);
+ EXPECT_EQ(gfx::PointF(2.5f, -1.5f), TransposePoint(p));
+ p.Transpose();
+ EXPECT_EQ(gfx::PointF(2.5f, -1.5f), p);
+}
+
+TEST(PointFTest, ToString) {
+ EXPECT_EQ("1,2", PointF(1, 2).ToString());
+ EXPECT_EQ("1.03125,2.5", PointF(1.03125, 2.5).ToString());
+}
+
+} // namespace gfx
diff --git a/ui/gfx/geometry/point_unittest.cc b/ui/gfx/geometry/point_unittest.cc
index 90f61ae..829216e 100644
--- a/ui/gfx/geometry/point_unittest.cc
+++ b/ui/gfx/geometry/point_unittest.cc
@@ -1,26 +1,14 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <stddef.h>
-
-#include "base/cxx17_backports.h"
-#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/point_conversions.h"
-#include "ui/gfx/geometry/point_f.h"
+
+#include <stddef.h>
+#include "testing/gtest/include/gtest/gtest.h"
namespace gfx {
-TEST(PointTest, ToPointF) {
- // Check that explicit conversion from integer to float compiles.
- Point a(10, 20);
- PointF b = PointF(a);
-
- EXPECT_EQ(static_cast<float>(a.x()), b.x());
- EXPECT_EQ(static_cast<float>(a.y()), b.y());
-}
-
TEST(PointTest, IsOrigin) {
EXPECT_FALSE(Point(1, 0).IsOrigin());
EXPECT_FALSE(Point(0, 1).IsOrigin());
@@ -29,14 +17,6 @@
EXPECT_FALSE(Point(0, -1).IsOrigin());
EXPECT_FALSE(Point(-1, -2).IsOrigin());
EXPECT_TRUE(Point(0, 0).IsOrigin());
-
- EXPECT_FALSE(PointF(0.1f, 0).IsOrigin());
- EXPECT_FALSE(PointF(0, 0.1f).IsOrigin());
- EXPECT_FALSE(PointF(0.1f, 2).IsOrigin());
- EXPECT_FALSE(PointF(-0.1f, 0).IsOrigin());
- EXPECT_FALSE(PointF(0, -0.1f).IsOrigin());
- EXPECT_FALSE(PointF(-0.1f, -2).IsOrigin());
- EXPECT_TRUE(PointF(0, 0).IsOrigin());
}
TEST(PointTest, VectorArithmetic) {
@@ -57,107 +37,40 @@
{ Point(-10, 9), a - v1 + v2 }
};
- for (size_t i = 0; i < base::size(tests); ++i)
- EXPECT_EQ(tests[i].expected.ToString(), tests[i].actual.ToString());
+ for (auto& test : tests)
+ EXPECT_EQ(test.expected, test.actual);
}
TEST(PointTest, OffsetFromPoint) {
Point a(1, 5);
Point b(-20, 8);
- EXPECT_EQ(Vector2d(-20 - 1, 8 - 5).ToString(), (b - a).ToString());
+ EXPECT_EQ(Vector2d(-20 - 1, 8 - 5), (b - a));
}
-TEST(PointTest, ToRoundedPoint) {
- EXPECT_EQ(Point(0, 0), ToRoundedPoint(PointF(0, 0)));
- EXPECT_EQ(Point(0, 0), ToRoundedPoint(PointF(0.0001f, 0.0001f)));
- EXPECT_EQ(Point(0, 0), ToRoundedPoint(PointF(0.4999f, 0.4999f)));
- EXPECT_EQ(Point(1, 1), ToRoundedPoint(PointF(0.5f, 0.5f)));
- EXPECT_EQ(Point(1, 1), ToRoundedPoint(PointF(0.9999f, 0.9999f)));
-
- EXPECT_EQ(Point(10, 10), ToRoundedPoint(PointF(10, 10)));
- EXPECT_EQ(Point(10, 10), ToRoundedPoint(PointF(10.0001f, 10.0001f)));
- EXPECT_EQ(Point(10, 10), ToRoundedPoint(PointF(10.4999f, 10.4999f)));
- EXPECT_EQ(Point(11, 11), ToRoundedPoint(PointF(10.5f, 10.5f)));
- EXPECT_EQ(Point(11, 11), ToRoundedPoint(PointF(10.9999f, 10.9999f)));
-
- EXPECT_EQ(Point(-10, -10), ToRoundedPoint(PointF(-10, -10)));
- EXPECT_EQ(Point(-10, -10), ToRoundedPoint(PointF(-10.0001f, -10.0001f)));
- EXPECT_EQ(Point(-10, -10), ToRoundedPoint(PointF(-10.4999f, -10.4999f)));
- EXPECT_EQ(Point(-11, -11), ToRoundedPoint(PointF(-10.5f, -10.5f)));
- EXPECT_EQ(Point(-11, -11), ToRoundedPoint(PointF(-10.9999f, -10.9999f)));
-}
-
-TEST(PointTest, Scale) {
- EXPECT_EQ(PointF().ToString(), ScalePoint(PointF(), 2).ToString());
- EXPECT_EQ(PointF().ToString(), ScalePoint(PointF(), 2, 2).ToString());
-
- EXPECT_EQ(PointF(2, -2).ToString(), ScalePoint(PointF(1, -1), 2).ToString());
- EXPECT_EQ(PointF(2, -2).ToString(),
- ScalePoint(PointF(1, -1), 2, 2).ToString());
-
- PointF zero;
- PointF one(1, -1);
-
- zero.Scale(2);
- zero.Scale(3, 1.5);
-
- one.Scale(2);
- one.Scale(3, 1.5);
-
- EXPECT_EQ(PointF().ToString(), zero.ToString());
- EXPECT_EQ(PointF(6, -3).ToString(), one.ToString());
-}
-
-TEST(PointTest, ClampPoint) {
+TEST(PointTest, SetToMinMax) {
Point a;
a = Point(3, 5);
- EXPECT_EQ(Point(3, 5).ToString(), a.ToString());
+ EXPECT_EQ(Point(3, 5), a);
a.SetToMax(Point(2, 4));
- EXPECT_EQ(Point(3, 5).ToString(), a.ToString());
+ EXPECT_EQ(Point(3, 5), a);
a.SetToMax(Point(3, 5));
- EXPECT_EQ(Point(3, 5).ToString(), a.ToString());
+ EXPECT_EQ(Point(3, 5), a);
a.SetToMax(Point(4, 2));
- EXPECT_EQ(Point(4, 5).ToString(), a.ToString());
+ EXPECT_EQ(Point(4, 5), a);
a.SetToMax(Point(8, 10));
- EXPECT_EQ(Point(8, 10).ToString(), a.ToString());
+ EXPECT_EQ(Point(8, 10), a);
a.SetToMin(Point(9, 11));
- EXPECT_EQ(Point(8, 10).ToString(), a.ToString());
+ EXPECT_EQ(Point(8, 10), a);
a.SetToMin(Point(8, 10));
- EXPECT_EQ(Point(8, 10).ToString(), a.ToString());
+ EXPECT_EQ(Point(8, 10), a);
a.SetToMin(Point(11, 9));
- EXPECT_EQ(Point(8, 9).ToString(), a.ToString());
+ EXPECT_EQ(Point(8, 9), a);
a.SetToMin(Point(7, 11));
- EXPECT_EQ(Point(7, 9).ToString(), a.ToString());
+ EXPECT_EQ(Point(7, 9), a);
a.SetToMin(Point(3, 5));
- EXPECT_EQ(Point(3, 5).ToString(), a.ToString());
-}
-
-TEST(PointTest, ClampPointF) {
- PointF a;
-
- a = PointF(3.5f, 5.5f);
- EXPECT_EQ(PointF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(PointF(2.5f, 4.5f));
- EXPECT_EQ(PointF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(PointF(3.5f, 5.5f));
- EXPECT_EQ(PointF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(PointF(4.5f, 2.5f));
- EXPECT_EQ(PointF(4.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(PointF(8.5f, 10.5f));
- EXPECT_EQ(PointF(8.5f, 10.5f).ToString(), a.ToString());
-
- a.SetToMin(PointF(9.5f, 11.5f));
- EXPECT_EQ(PointF(8.5f, 10.5f).ToString(), a.ToString());
- a.SetToMin(PointF(8.5f, 10.5f));
- EXPECT_EQ(PointF(8.5f, 10.5f).ToString(), a.ToString());
- a.SetToMin(PointF(11.5f, 9.5f));
- EXPECT_EQ(PointF(8.5f, 9.5f).ToString(), a.ToString());
- a.SetToMin(PointF(7.5f, 11.5f));
- EXPECT_EQ(PointF(7.5f, 9.5f).ToString(), a.ToString());
- a.SetToMin(PointF(3.5f, 5.5f));
- EXPECT_EQ(PointF(3.5f, 5.5f).ToString(), a.ToString());
+ EXPECT_EQ(Point(3, 5), a);
}
TEST(PointTest, Offset) {
@@ -233,23 +146,11 @@
EXPECT_EQ(test, min_point);
}
-TEST(PointTest, IsWithinDistance) {
- PointF pt(10.f, 10.f);
- EXPECT_TRUE(pt.IsWithinDistance(PointF(10.f, 10.f),
- /*allowed_distance=*/0.0000000000001f));
- EXPECT_FALSE(pt.IsWithinDistance(PointF(8.f, 8.f), /*allowed_distance=*/1.f));
-
- pt = PointF(-10.f, -10.f);
- EXPECT_FALSE(
- pt.IsWithinDistance(PointF(10.f, 10.f), /*allowed_distance=*/10.f));
- EXPECT_TRUE(pt.IsWithinDistance(PointF(-9.9988f, -10.0013f),
- /*epsallowed_distanceilon=*/0.0017689f));
-
- pt = PointF(std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max());
- EXPECT_FALSE(pt.IsWithinDistance(PointF(std::numeric_limits<float>::min(),
- std::numeric_limits<float>::min()),
- /*allowed_distance=*/100.f));
+TEST(PointTest, Transpose) {
+ gfx::Point p(1, -2);
+ EXPECT_EQ(gfx::Point(-2, 1), TransposePoint(p));
+ p.Transpose();
+ EXPECT_EQ(gfx::Point(-2, 1), p);
}
} // namespace gfx
diff --git a/ui/gfx/geometry/quad_f.cc b/ui/gfx/geometry/quad_f.cc
index 8ed8b91..e7915fc 100644
--- a/ui/gfx/geometry/quad_f.cc
+++ b/ui/gfx/geometry/quad_f.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,9 +7,67 @@
#include <limits>
#include "base/strings/stringprintf.h"
+#include "ui/gfx/geometry/triangle_f.h"
namespace gfx {
+namespace {
+
+PointF RightMostCornerToVector(const RectF& rect, const Vector2dF& vector) {
+ // Return the corner of the rectangle that if it is to the left of the vector
+ // would mean all of the rectangle is to the left of the vector.
+ // The vector here represents the side between two points in a clockwise
+ // convex polygon.
+ //
+ // Q XXX
+ // QQQ XXX If the lower left corner of X is left of the vector that goes
+ // QQQ from the top corner of Q to the right corner of Q, then all of X
+ // Q is left of the vector, and intersection impossible.
+ //
+ PointF point;
+ if (vector.x() >= 0)
+ point.set_y(rect.bottom());
+ else
+ point.set_y(rect.y());
+ if (vector.y() >= 0)
+ point.set_x(rect.x());
+ else
+ point.set_x(rect.right());
+ return point;
+}
+
+// Tests whether the line is contained by or intersected with the circle.
+bool LineIntersectsCircle(const PointF& center,
+ float radius,
+ const PointF& p0,
+ const PointF& p1) {
+ float x0 = p0.x() - center.x(), y0 = p0.y() - center.y();
+ float x1 = p1.x() - center.x(), y1 = p1.y() - center.y();
+ float radius2 = radius * radius;
+ if ((x0 * x0 + y0 * y0) <= radius2 || (x1 * x1 + y1 * y1) <= radius2)
+ return true;
+ if (p0 == p1)
+ return false;
+
+ float a = y0 - y1;
+ float b = x1 - x0;
+ float c = x0 * y1 - x1 * y0;
+ float distance2 = c * c / (a * a + b * b);
+ // If distance between the center point and the line > the radius,
+ // the line doesn't cross (or is contained by) the ellipse.
+ if (distance2 > radius2)
+ return false;
+
+ // The nearest point on the line is between p0 and p1?
+ float x = -a * c / (a * a + b * b);
+ float y = -b * c / (a * a + b * b);
+
+ return (((x0 <= x && x <= x1) || (x0 >= x && x >= x1)) &&
+ ((y0 <= y && y <= y1) || (y1 <= y && y <= y0)));
+}
+
+} // anonymous namespace
+
void QuadF::operator=(const RectF& rect) {
p1_ = PointF(rect.x(), rect.y());
p2_ = PointF(rect.right(), rect.y());
@@ -62,40 +120,14 @@
return element1 + element2 < element3 + element4;
}
-static inline bool PointIsInTriangle(const PointF& point,
- const PointF& r1,
- const PointF& r2,
- const PointF& r3) {
- // Compute the barycentric coordinates (u, v, w) of |point| relative to the
- // triangle (r1, r2, r3) by the solving the system of equations:
- // 1) point = u * r1 + v * r2 + w * r3
- // 2) u + v + w = 1
- // This algorithm comes from Christer Ericson's Real-Time Collision Detection.
-
- Vector2dF r31 = r1 - r3;
- Vector2dF r32 = r2 - r3;
- Vector2dF r3p = point - r3;
-
- // Promote to doubles so all the math below is done with doubles, because
- // otherwise it gets incorrect results on arm64.
- double r31x = r31.x();
- double r31y = r31.y();
- double r32x = r32.x();
- double r32y = r32.y();
-
- double denom = r32y * r31x - r32x * r31y;
- double u = (r32y * r3p.x() - r32x * r3p.y()) / denom;
- double v = (r31x * r3p.y() - r31y * r3p.x()) / denom;
- double w = 1.0 - u - v;
-
- // Use the barycentric coordinates to test if |point| is inside the
- // triangle (r1, r2, r2).
- return (u >= 0) && (v >= 0) && (w >= 0);
+bool QuadF::Contains(const PointF& point) const {
+ return PointIsInTriangle(point, p1_, p2_, p3_) ||
+ PointIsInTriangle(point, p1_, p3_, p4_);
}
-bool QuadF::Contains(const PointF& point) const {
- return PointIsInTriangle(point, p1_, p2_, p3_)
- || PointIsInTriangle(point, p1_, p3_, p4_);
+bool QuadF::ContainsQuad(const QuadF& other) const {
+ return Contains(other.p1()) && Contains(other.p2()) && Contains(other.p3()) &&
+ Contains(other.p4());
}
void QuadF::Scale(float x_scale, float y_scale) {
@@ -131,4 +163,64 @@
return result;
}
+bool QuadF::IntersectsRect(const RectF& rect) const {
+ // For each side of the quad clockwise we check if the rectangle is to the
+ // left of it since only content on the right can overlap with the quad.
+ // This only works if the quad is convex.
+ Vector2dF v1, v2, v3, v4;
+
+ // Ensure we use clockwise vectors.
+ if (IsCounterClockwise()) {
+ v1 = p4_ - p1_;
+ v2 = p1_ - p2_;
+ v3 = p2_ - p3_;
+ v4 = p3_ - p4_;
+ } else {
+ v1 = p2_ - p1_;
+ v2 = p3_ - p2_;
+ v3 = p4_ - p3_;
+ v4 = p1_ - p4_;
+ }
+
+ PointF p = RightMostCornerToVector(rect, v1);
+ if (CrossProduct(v1, p - p1_) < 0)
+ return false;
+
+ p = RightMostCornerToVector(rect, v2);
+ if (CrossProduct(v2, p - p2_) < 0)
+ return false;
+
+ p = RightMostCornerToVector(rect, v3);
+ if (CrossProduct(v3, p - p3_) < 0)
+ return false;
+
+ p = RightMostCornerToVector(rect, v4);
+ if (CrossProduct(v4, p - p4_) < 0)
+ return false;
+
+ // If not all of the rectangle is outside one of the quad's four sides, then
+ // that means at least a part of the rectangle is overlapping the quad.
+ return true;
+}
+
+bool QuadF::IntersectsCircle(const PointF& center, float radius) const {
+ return Contains(center) || LineIntersectsCircle(center, radius, p1_, p2_) ||
+ LineIntersectsCircle(center, radius, p2_, p3_) ||
+ LineIntersectsCircle(center, radius, p3_, p4_) ||
+ LineIntersectsCircle(center, radius, p4_, p1_);
+}
+
+bool QuadF::IntersectsEllipse(const PointF& center, const SizeF& radii) const {
+ // Transform the ellipse to an origin-centered circle whose radius is the
+ // product of major radius and minor radius. Here we apply the same
+ // transformation to the quad.
+ QuadF transformed_quad = *this;
+ transformed_quad -= center.OffsetFromOrigin();
+ transformed_quad.Scale(radii.height(), radii.width());
+
+ PointF origin_point;
+ return transformed_quad.IntersectsCircle(origin_point,
+ radii.height() * radii.width());
+}
+
} // namespace gfx
diff --git a/ui/gfx/geometry/quad_f.h b/ui/gfx/geometry/quad_f.h
index 3fe8cf1..4194fc3 100644
--- a/ui/gfx/geometry/quad_f.h
+++ b/ui/gfx/geometry/quad_f.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -57,7 +57,12 @@
// Returns true if the |point| is contained within the quad, or lies on on
// edge of the quad. This assumes that the quad is convex.
- bool Contains(const gfx::PointF& point) const;
+ bool Contains(const PointF& point) const;
+
+ // Returns true if the |quad| parameter is contained within |this| quad.
+ // This method assumes |this| quad is convex. The |quad| parameter has no
+ // restrictions.
+ bool ContainsQuad(const QuadF& quad) const;
// Returns a rectangle that bounds the four points of the quad. The points of
// the quad may lie on the right/bottom edge of the resulting rectangle,
@@ -94,6 +99,26 @@
// Scale each point in the quad by the scale factors along each axis.
void Scale(float x_scale, float y_scale);
+ // Tests whether any part of the rectangle intersects with this quad.
+ // This only works for convex quads.
+ // This intersection is edge-inclusive and will return true even if the
+ // intersecting area is empty (i.e., the intersection is a line or a point).
+ bool IntersectsRect(const RectF&) const;
+
+ // Test whether any part of the circle/ellipse intersects with this quad.
+ // Note that these two functions only work for convex quads.
+ // These intersections are edge-inclusive and will return true even if the
+ // intersecting area is empty (i.e., the intersection is a line or a point).
+ bool IntersectsCircle(const PointF& center, float radius) const;
+ bool IntersectsEllipse(const PointF& center, const SizeF& radii) const;
+
+ // The center of the quad. If the quad is the result of a affine-transformed
+ // rectangle this is the same as the original center transformed.
+ PointF CenterPoint() const {
+ return PointF((p1_.x() + p2_.x() + p3_.x() + p4_.x()) / 4.0,
+ (p1_.y() + p2_.y() + p3_.y() + p4_.y()) / 4.0);
+ }
+
// Returns a string representation of quad.
std::string ToString() const;
diff --git a/ui/gfx/geometry/quad_f_unittest.cc b/ui/gfx/geometry/quad_f_unittest.cc
new file mode 100644
index 0000000..985aeb2
--- /dev/null
+++ b/ui/gfx/geometry/quad_f_unittest.cc
@@ -0,0 +1,717 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+
+#include "base/cxx17_backports.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/quad_f.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/transform.h"
+
+namespace gfx {
+
+TEST(QuadFTest, Construction) {
+ // Verify constructors.
+ PointF a(1, 1);
+ PointF b(2, 1);
+ PointF c(2, 2);
+ PointF d(1, 2);
+ PointF e;
+ QuadF q1;
+ QuadF q2(e, e, e, e);
+ QuadF q3(a, b, c, d);
+ QuadF q4(BoundingRect(a, c));
+ EXPECT_EQ(q1, q2);
+ EXPECT_EQ(q3, q4);
+
+ // Verify getters.
+ EXPECT_EQ(q3.p1(), a);
+ EXPECT_EQ(q3.p2(), b);
+ EXPECT_EQ(q3.p3(), c);
+ EXPECT_EQ(q3.p4(), d);
+
+ // Verify setters.
+ q3.set_p1(b);
+ q3.set_p2(c);
+ q3.set_p3(d);
+ q3.set_p4(a);
+ EXPECT_EQ(q3.p1(), b);
+ EXPECT_EQ(q3.p2(), c);
+ EXPECT_EQ(q3.p3(), d);
+ EXPECT_EQ(q3.p4(), a);
+
+ // Verify operator=(Rect)
+ EXPECT_NE(q1, q4);
+ q1 = BoundingRect(a, c);
+ EXPECT_EQ(q1, q4);
+
+ // Verify operator=(Quad)
+ EXPECT_NE(q1, q3);
+ q1 = q3;
+ EXPECT_EQ(q1, q3);
+}
+
+TEST(QuadFTest, AddingVectors) {
+ PointF a(1, 1);
+ PointF b(2, 1);
+ PointF c(2, 2);
+ PointF d(1, 2);
+ Vector2dF v(3.5f, -2.5f);
+
+ QuadF q1(a, b, c, d);
+ QuadF added = q1 + v;
+ q1 += v;
+ QuadF expected1(PointF(4.5f, -1.5f), PointF(5.5f, -1.5f), PointF(5.5f, -0.5f),
+ PointF(4.5f, -0.5f));
+ EXPECT_EQ(expected1, added);
+ EXPECT_EQ(expected1, q1);
+
+ QuadF q2(a, b, c, d);
+ QuadF subtracted = q2 - v;
+ q2 -= v;
+ QuadF expected2(PointF(-2.5f, 3.5f), PointF(-1.5f, 3.5f), PointF(-1.5f, 4.5f),
+ PointF(-2.5f, 4.5f));
+ EXPECT_EQ(expected2, subtracted);
+ EXPECT_EQ(expected2, q2);
+
+ QuadF q3(a, b, c, d);
+ q3 += v;
+ q3 -= v;
+ EXPECT_EQ(QuadF(a, b, c, d), q3);
+ EXPECT_EQ(q3, (q3 + v - v));
+}
+
+TEST(QuadFTest, IsRectilinear) {
+ PointF a(1, 1);
+ PointF b(2, 1);
+ PointF c(2, 2);
+ PointF d(1, 2);
+ Vector2dF v(3.5f, -2.5f);
+
+ EXPECT_TRUE(QuadF().IsRectilinear());
+ EXPECT_TRUE(QuadF(a, b, c, d).IsRectilinear());
+ EXPECT_TRUE((QuadF(a, b, c, d) + v).IsRectilinear());
+
+ float epsilon = std::numeric_limits<float>::epsilon();
+ PointF a2(1 + epsilon / 2, 1 + epsilon / 2);
+ PointF b2(2 + epsilon / 2, 1 + epsilon / 2);
+ PointF c2(2 + epsilon / 2, 2 + epsilon / 2);
+ PointF d2(1 + epsilon / 2, 2 + epsilon / 2);
+ EXPECT_TRUE(QuadF(a2, b, c, d).IsRectilinear());
+ EXPECT_TRUE((QuadF(a2, b, c, d) + v).IsRectilinear());
+ EXPECT_TRUE(QuadF(a, b2, c, d).IsRectilinear());
+ EXPECT_TRUE((QuadF(a, b2, c, d) + v).IsRectilinear());
+ EXPECT_TRUE(QuadF(a, b, c2, d).IsRectilinear());
+ EXPECT_TRUE((QuadF(a, b, c2, d) + v).IsRectilinear());
+ EXPECT_TRUE(QuadF(a, b, c, d2).IsRectilinear());
+ EXPECT_TRUE((QuadF(a, b, c, d2) + v).IsRectilinear());
+
+ struct {
+ PointF a_off, b_off, c_off, d_off;
+ } tests[] = {{PointF(1, 1.00001f), PointF(2, 1.00001f), PointF(2, 2.00001f),
+ PointF(1, 2.00001f)},
+ {PointF(1.00001f, 1), PointF(2.00001f, 1), PointF(2.00001f, 2),
+ PointF(1.00001f, 2)},
+ {PointF(1.00001f, 1.00001f), PointF(2.00001f, 1.00001f),
+ PointF(2.00001f, 2.00001f), PointF(1.00001f, 2.00001f)},
+ {PointF(1, 0.99999f), PointF(2, 0.99999f), PointF(2, 1.99999f),
+ PointF(1, 1.99999f)},
+ {PointF(0.99999f, 1), PointF(1.99999f, 1), PointF(1.99999f, 2),
+ PointF(0.99999f, 2)},
+ {PointF(0.99999f, 0.99999f), PointF(1.99999f, 0.99999f),
+ PointF(1.99999f, 1.99999f), PointF(0.99999f, 1.99999f)}};
+
+ for (const auto& test : tests) {
+ PointF a_off = test.a_off;
+ PointF b_off = test.b_off;
+ PointF c_off = test.c_off;
+ PointF d_off = test.d_off;
+
+ EXPECT_FALSE(QuadF(a_off, b, c, d).IsRectilinear());
+ EXPECT_FALSE((QuadF(a_off, b, c, d) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a, b_off, c, d).IsRectilinear());
+ EXPECT_FALSE((QuadF(a, b_off, c, d) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a, b, c_off, d).IsRectilinear());
+ EXPECT_FALSE((QuadF(a, b, c_off, d) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a, b, c, d_off).IsRectilinear());
+ EXPECT_FALSE((QuadF(a, b, c, d_off) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a_off, b, c_off, d).IsRectilinear());
+ EXPECT_FALSE((QuadF(a_off, b, c_off, d) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a, b_off, c, d_off).IsRectilinear());
+ EXPECT_FALSE((QuadF(a, b_off, c, d_off) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a, b_off, c_off, d_off).IsRectilinear());
+ EXPECT_FALSE((QuadF(a, b_off, c_off, d_off) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a_off, b, c_off, d_off).IsRectilinear());
+ EXPECT_FALSE((QuadF(a_off, b, c_off, d_off) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a_off, b_off, c, d_off).IsRectilinear());
+ EXPECT_FALSE((QuadF(a_off, b_off, c, d_off) + v).IsRectilinear());
+ EXPECT_FALSE(QuadF(a_off, b_off, c_off, d).IsRectilinear());
+ EXPECT_FALSE((QuadF(a_off, b_off, c_off, d) + v).IsRectilinear());
+ EXPECT_TRUE(QuadF(a_off, b_off, c_off, d_off).IsRectilinear());
+ EXPECT_TRUE((QuadF(a_off, b_off, c_off, d_off) + v).IsRectilinear());
+ }
+}
+
+TEST(QuadFTest, IsRectilinearForMappedQuad) {
+ const int kNumRectilinear = 8;
+ Transform rectilinear_trans[kNumRectilinear];
+ rectilinear_trans[1].Rotate(90.f);
+ rectilinear_trans[2].Rotate(180.f);
+ rectilinear_trans[3].Rotate(270.f);
+ rectilinear_trans[4].Skew(0.00000000001f, 0.0f);
+ rectilinear_trans[5].Skew(0.0f, 0.00000000001f);
+ rectilinear_trans[6].Scale(0.00001f, 0.00001f);
+ rectilinear_trans[6].Rotate(180.f);
+ rectilinear_trans[7].Scale(100000.f, 100000.f);
+ rectilinear_trans[7].Rotate(180.f);
+
+ gfx::QuadF original(
+ gfx::RectF(0.01010101f, 0.01010101f, 100.01010101f, 100.01010101f));
+
+ for (int i = 0; i < kNumRectilinear; ++i) {
+ gfx::QuadF quad = rectilinear_trans[i].MapQuad(original);
+ EXPECT_TRUE(quad.IsRectilinear()) << "case " << i;
+ }
+
+ const int kNumNonRectilinear = 10;
+ gfx::Transform non_rectilinear_trans[kNumNonRectilinear];
+ non_rectilinear_trans[0].Rotate(359.9999f);
+ non_rectilinear_trans[1].Rotate(0.0000001f);
+ non_rectilinear_trans[2].Rotate(89.9999f);
+ non_rectilinear_trans[3].Rotate(90.00001f);
+ non_rectilinear_trans[4].Rotate(179.9999f);
+ non_rectilinear_trans[5].Rotate(180.00001f);
+ non_rectilinear_trans[6].Rotate(269.9999f);
+ non_rectilinear_trans[7].Rotate(270.0001f);
+ non_rectilinear_trans[8].Skew(0.00001f, 0.0f);
+ non_rectilinear_trans[9].Skew(0.0f, 0.00001f);
+
+ for (int i = 0; i < kNumNonRectilinear; ++i) {
+ gfx::QuadF quad = non_rectilinear_trans[i].MapQuad(original);
+ EXPECT_FALSE(quad.IsRectilinear()) << "case " << i;
+ }
+}
+
+TEST(QuadFTest, IsCounterClockwise) {
+ PointF a1(1, 1);
+ PointF b1(2, 1);
+ PointF c1(2, 2);
+ PointF d1(1, 2);
+ EXPECT_FALSE(QuadF(a1, b1, c1, d1).IsCounterClockwise());
+ EXPECT_FALSE(QuadF(b1, c1, d1, a1).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(a1, d1, c1, b1).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(c1, b1, a1, d1).IsCounterClockwise());
+
+ // Slightly more complicated quads should work just as easily.
+ PointF a2(1.3f, 1.4f);
+ PointF b2(-0.7f, 4.9f);
+ PointF c2(1.8f, 6.2f);
+ PointF d2(2.1f, 1.6f);
+ EXPECT_TRUE(QuadF(a2, b2, c2, d2).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(b2, c2, d2, a2).IsCounterClockwise());
+ EXPECT_FALSE(QuadF(a2, d2, c2, b2).IsCounterClockwise());
+ EXPECT_FALSE(QuadF(c2, b2, a2, d2).IsCounterClockwise());
+
+ // Quads with 3 collinear points should work correctly, too.
+ PointF a3(0, 0);
+ PointF b3(1, 0);
+ PointF c3(2, 0);
+ PointF d3(1, 1);
+ EXPECT_FALSE(QuadF(a3, b3, c3, d3).IsCounterClockwise());
+ EXPECT_FALSE(QuadF(b3, c3, d3, a3).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(a3, d3, c3, b3).IsCounterClockwise());
+ // The next expectation in particular would fail for an implementation
+ // that incorrectly uses only a cross product of the first 3 vertices.
+ EXPECT_TRUE(QuadF(c3, b3, a3, d3).IsCounterClockwise());
+
+ // Non-convex quads should work correctly, too.
+ PointF a4(0, 0);
+ PointF b4(1, 1);
+ PointF c4(2, 0);
+ PointF d4(1, 3);
+ EXPECT_FALSE(QuadF(a4, b4, c4, d4).IsCounterClockwise());
+ EXPECT_FALSE(QuadF(b4, c4, d4, a4).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(a4, d4, c4, b4).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(c4, b4, a4, d4).IsCounterClockwise());
+
+ // A quad with huge coordinates should not fail this check due to
+ // single-precision overflow.
+ PointF a5(1e30f, 1e30f);
+ PointF b5(1e35f, 1e30f);
+ PointF c5(1e35f, 1e35f);
+ PointF d5(1e30f, 1e35f);
+ EXPECT_FALSE(QuadF(a5, b5, c5, d5).IsCounterClockwise());
+ EXPECT_FALSE(QuadF(b5, c5, d5, a5).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(a5, d5, c5, b5).IsCounterClockwise());
+ EXPECT_TRUE(QuadF(c5, b5, a5, d5).IsCounterClockwise());
+}
+
+TEST(QuadFTest, BoundingBox) {
+ RectF r(3.2f, 5.4f, 7.007f, 12.01f);
+ EXPECT_EQ(r, QuadF(r).BoundingBox());
+
+ PointF a(1.3f, 1.4f);
+ PointF b(-0.7f, 4.9f);
+ PointF c(1.8f, 6.2f);
+ PointF d(2.1f, 1.6f);
+ float left = -0.7f;
+ float top = 1.4f;
+ float right = 2.1f;
+ float bottom = 6.2f;
+ EXPECT_EQ(RectF(left, top, right - left, bottom - top),
+ QuadF(a, b, c, d).BoundingBox());
+}
+
+TEST(QuadFTest, ContainsPoint) {
+ PointF a(1.3f, 1.4f);
+ PointF b(-0.8f, 4.4f);
+ PointF c(1.8f, 6.1f);
+ PointF d(2.1f, 1.6f);
+
+ Vector2dF epsilon_x(2 * std::numeric_limits<float>::epsilon(), 0);
+ Vector2dF epsilon_y(0, 2 * std::numeric_limits<float>::epsilon());
+
+ Vector2dF ac_center = c - a;
+ ac_center.Scale(0.5f);
+ Vector2dF bd_center = d - b;
+ bd_center.Scale(0.5f);
+
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(a + ac_center));
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(b + bd_center));
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(c - ac_center));
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(d - bd_center));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - ac_center));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - bd_center));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + ac_center));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + bd_center));
+
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(a));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - epsilon_x));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - epsilon_y));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(a + epsilon_x));
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(a + epsilon_y));
+
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(b));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - epsilon_x));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - epsilon_y));
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(b + epsilon_x));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(b + epsilon_y));
+
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(c));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(c - epsilon_x));
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(c - epsilon_y));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + epsilon_x));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + epsilon_y));
+
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(d));
+ EXPECT_TRUE(QuadF(a, b, c, d).Contains(d - epsilon_x));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(d - epsilon_y));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + epsilon_x));
+ EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + epsilon_y));
+
+ // Test a simple square.
+ PointF s1(-1, -1);
+ PointF s2(1, -1);
+ PointF s3(1, 1);
+ PointF s4(-1, 1);
+ // Top edge.
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, -1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0.0f, -1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.0f)));
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, -1.0f)));
+ // Bottom edge.
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, 1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0.0f, 1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.0f)));
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, 1.0f)));
+ // Left edge.
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.1f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 0.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.0f)));
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.1f)));
+ // Right edge.
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.1f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 0.0f)));
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.0f)));
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.1f)));
+ // Centered inside.
+ EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0, 0)));
+ // Centered outside.
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, 0)));
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, 0)));
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(0, -1.1f)));
+ EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(0, 1.1f)));
+}
+
+TEST(QuadFTest, ContainsQuad) {
+ QuadF quad(PointF(10, 0), PointF(20, 10), PointF(10, 20), PointF(0, 10));
+ EXPECT_TRUE(quad.ContainsQuad(quad));
+ EXPECT_TRUE(QuadF(quad.BoundingBox()).ContainsQuad(quad));
+ EXPECT_FALSE(quad.ContainsQuad(QuadF(quad.BoundingBox())));
+
+ EXPECT_FALSE(quad.ContainsQuad(QuadF(RectF(4.9, 4.9, 9.8, 9.8))));
+ EXPECT_TRUE(quad.ContainsQuad(QuadF(RectF(5.1, 5.1, 9.8, 9.8))));
+ EXPECT_FALSE(quad.ContainsQuad(QuadF(RectF(5.1, 5.1, 11, 9.8))));
+ EXPECT_FALSE(quad.ContainsQuad(QuadF(RectF(5.1, 5.1, 9.8, 11))));
+
+ EXPECT_FALSE(quad.ContainsQuad(quad + gfx::Vector2dF(0.1, 0)));
+ EXPECT_FALSE(quad.ContainsQuad(quad + gfx::Vector2dF(0, 0.1)));
+ EXPECT_FALSE(quad.ContainsQuad(quad - gfx::Vector2dF(0.1, 0)));
+ EXPECT_FALSE(quad.ContainsQuad(quad - gfx::Vector2dF(0, 0.1)));
+}
+
+TEST(QuadFTest, Scale) {
+ PointF a(1.3f, 1.4f);
+ PointF b(-0.8f, 4.4f);
+ PointF c(1.8f, 6.1f);
+ PointF d(2.1f, 1.6f);
+ QuadF q1(a, b, c, d);
+ q1.Scale(1.5f);
+
+ PointF a_scaled = ScalePoint(a, 1.5f);
+ PointF b_scaled = ScalePoint(b, 1.5f);
+ PointF c_scaled = ScalePoint(c, 1.5f);
+ PointF d_scaled = ScalePoint(d, 1.5f);
+ EXPECT_EQ(q1, QuadF(a_scaled, b_scaled, c_scaled, d_scaled));
+
+ QuadF q2;
+ q2.Scale(1.5f);
+ EXPECT_EQ(q2, q2);
+}
+
+TEST(QuadFTest, IntersectsRectClockwise) {
+ QuadF quad(PointF(10, 0), PointF(20, 10), PointF(10, 20), PointF(0, 10));
+
+ // Top-left.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, 0, 4.9, 4.9)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 0, 4.9, 6)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 0, 5.1, 5.1)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 0, 6, 4.9)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, 0, 2, 6)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, 0, 6, 2)));
+
+ // Top.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, -30, 20, 2)));
+ // TODO(crbug.com/1283709): For now the result is true.
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(0, -5, 20, 2)));
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(0, -5, 20, 4.9)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, -5, 20, 5.1)));
+
+ // Top-right.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(15.1, 0, 10, 4.9)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(15.1, 0, 10, 6)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(14.9, 0, 10, 5.1)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(14, 0, 10, 4.9)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(18, 0, 10, 6)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(14, 0, 10, 2)));
+
+ // Right.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(50, 0, 2, 20)));
+ // TODO(crbug.com/1283709): For now the result is true.
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(22, 0, 2, 20)));
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(20.1, 0, 2, 20)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(19.9, 0, 2, 20)));
+
+ // Bottom-right.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(15.1, 15.1, 10, 10)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(15.1, 14, 10, 10)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(14.9, 14.9, 10, 10)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(14, 15.1, 10, 10)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(18, 14, 10, 10)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(14, 18, 10, 10)));
+
+ // Bottom.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, 50, 20, 2)));
+ // TODO(crbug.com/1283709): For now the result is true.
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(0, 22, 20, 2)));
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(0, 20.1, 20, 2)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 19.9, 20, 2)));
+
+ // Bottom-left.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, 15.1, 4.9, 10)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 15.1, 6, 10)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 14.9, 5.1, 10)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 14, 4.9, 10)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, 18, 6, 10)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, 14, 2, 10)));
+
+ // Left.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(-30, 0, 2, 20)));
+ // TODO(crbug.com/1283709): For now the result is true.
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(-5, 0, 2, 20)));
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(-5, 0, 4.9, 20)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(-5, 0, 5.1, 20)));
+
+ // Cover.
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 0, 20, 20)));
+}
+
+TEST(QuadFTest, IntersectsRectCounterClockwise) {
+ QuadF quad(PointF(10, 0), PointF(0, 10), PointF(10, 20), PointF(20, 10));
+
+ // Top-left.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, 0, 4.9, 4.9)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 0, 4.9, 6)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 0, 5.1, 5.1)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 0, 6, 4.9)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, 0, 2, 6)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, 0, 6, 2)));
+
+ // Top.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, -30, 20, 2)));
+ // TODO(crbug.com/1283709): For now the result is true.
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(0, -5, 20, 2)));
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(0, -5, 20, 4.9)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, -5, 20, 5.1)));
+
+ // Top-right.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(15.1, 0, 10, 4.9)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(15.1, 0, 10, 6)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(14.9, 0, 10, 5.1)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(14, 0, 10, 4.9)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(18, 0, 10, 6)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(14, 0, 10, 2)));
+
+ // Right.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(50, 0, 2, 20)));
+ // TODO(crbug.com/1283709): For now the result is true.
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(22, 0, 2, 20)));
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(20.1, 0, 2, 20)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(19.9, 0, 2, 20)));
+
+ // Bottom-right.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(15.1, 15.1, 10, 10)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(15.1, 14, 10, 10)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(14.9, 14.9, 10, 10)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(14, 15.1, 10, 10)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(18, 14, 10, 10)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(14, 18, 10, 10)));
+
+ // Bottom.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, 50, 20, 2)));
+ // TODO(crbug.com/1283709): For now the result is true.
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(0, 22, 20, 2)));
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(0, 20.1, 20, 2)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 19.9, 20, 2)));
+
+ // Bottom-left.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, 15.1, 4.9, 10)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 15.1, 6, 10)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 14.9, 5.1, 10)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 14, 4.9, 10)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, 18, 6, 10)));
+ EXPECT_FALSE(quad.IntersectsRect(RectF(0, 14, 2, 10)));
+
+ // Left.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(-30, 0, 2, 20)));
+ // TODO(crbug.com/1283709): For now the result is true.
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(-5, 0, 2, 20)));
+ // EXPECT_FALSE(quad.IntersectsRect(RectF(-5, 0, 4.9, 20)));
+ EXPECT_TRUE(quad.IntersectsRect(RectF(-5, 0, 5.1, 20)));
+
+ // Cover.
+ EXPECT_TRUE(quad.IntersectsRect(RectF(0, 0, 20, 20)));
+}
+
+TEST(QuadFTest, RectIntersectionIsInclusive) {
+ // A rectilinear quad at (10, 10) with dimensions 10x10.
+ QuadF quad(RectF(10, 10, 10, 10));
+
+ // A rect fully contained in the quad should intersect.
+ EXPECT_TRUE(quad.IntersectsRect(RectF(11, 11, 8, 8)));
+
+ // A point fully contained in the quad should intersect.
+ EXPECT_TRUE(quad.IntersectsRect(RectF(11, 11, 0, 0)));
+
+ // A rect that touches the quad only at the point (10, 10) should intersect.
+ EXPECT_TRUE(quad.IntersectsRect(RectF(9, 9, 1, 1)));
+
+ // A rect that touches the quad only on the left edge should intersect.
+ EXPECT_TRUE(quad.IntersectsRect(RectF(9, 11, 1, 1)));
+
+ // A rect that touches the quad only on the top edge should intersect.
+ EXPECT_TRUE(quad.IntersectsRect(RectF(11, 9, 1, 1)));
+
+ // A rect that touches the quad only on the right edge should intersect.
+ EXPECT_TRUE(quad.IntersectsRect(RectF(20, 11, 1, 1)));
+
+ // A rect that touches the quad only on the bottom edge should intersect.
+ EXPECT_TRUE(quad.IntersectsRect(RectF(11, 20, 1, 1)));
+
+ // A rect that is fully outside the quad should not intersect.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(8, 8, 1, 1)));
+
+ // A point that is fully outside the quad should not intersect.
+ EXPECT_FALSE(quad.IntersectsRect(RectF(9, 9, 0, 0)));
+}
+
+TEST(QuadFTest, IntersectsEllipseClockWise) {
+ QuadF quad(PointF(10, 0), PointF(20, 10), PointF(10, 20), PointF(0, 10));
+
+ // Top-left.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(0, 0), SizeF(7, 7)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(0, 0), SizeF(6, 9)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(0, 0), SizeF(7.1, 7.1)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(0, 0), SizeF(9, 6)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(0, 0), SizeF(2, 8)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(0, 0), SizeF(8, 2)));
+
+ // Top.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(10, -5), SizeF(20, 2)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(10, -5), SizeF(20, 4.9)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(10, -5), SizeF(20, 5.1)));
+
+ // Top-right.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(20, 0), SizeF(7, 7)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(20, 0), SizeF(6, 9)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(20, 0), SizeF(7.1, 7.1)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(20, 0), SizeF(9, 6)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(20, 0), SizeF(2, 8)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(20, 0), SizeF(8, 2)));
+
+ // Right.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(25, 10), SizeF(2, 20)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(25, 10), SizeF(4.9, 20)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(25, 10), SizeF(5.1, 20)));
+
+ // Bottom-right.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(20, 20), SizeF(7, 7)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(20, 20), SizeF(6, 9)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(20, 20), SizeF(7.1, 7.1)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(20, 20), SizeF(9, 6)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(20, 20), SizeF(2, 8)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(20, 20), SizeF(8, 2)));
+
+ // Bottom.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(10, 25), SizeF(20, 2)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(10, 25), SizeF(20, 4.9)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(10, 25), SizeF(20, 5.1)));
+
+ // Bottom-left.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(0, 20), SizeF(7, 7)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(0, 20), SizeF(6, 9)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(0, 20), SizeF(7.1, 7.1)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(0, 20), SizeF(9, 6)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(0, 20), SizeF(2, 8)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(0, 20), SizeF(8, 2)));
+
+ // Left.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(-5, 10), SizeF(2, 20)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(-5, 10), SizeF(4.9, 20)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(-5, 10), SizeF(5.1, 20)));
+}
+
+TEST(QuadFTest, IntersectsEllipseCounterClockwise) {
+ QuadF quad(PointF(10, 0), PointF(0, 10), PointF(10, 20), PointF(20, 10));
+
+ // Top-left.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(0, 0), SizeF(7, 7)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(0, 0), SizeF(6, 9)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(0, 0), SizeF(7.1, 7.1)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(0, 0), SizeF(9, 6)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(0, 0), SizeF(2, 8)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(0, 0), SizeF(8, 2)));
+
+ // Top.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(10, -5), SizeF(20, 2)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(10, -5), SizeF(20, 4.9)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(10, -5), SizeF(20, 5.1)));
+
+ // Top-right.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(20, 0), SizeF(7, 7)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(20, 0), SizeF(6, 9)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(20, 0), SizeF(7.1, 7.1)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(20, 0), SizeF(9, 6)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(20, 0), SizeF(2, 8)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(20, 0), SizeF(8, 2)));
+
+ // Right.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(25, 10), SizeF(2, 20)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(25, 10), SizeF(4.9, 20)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(25, 10), SizeF(5.1, 20)));
+
+ // Bottom-right.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(20, 20), SizeF(7, 7)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(20, 20), SizeF(6, 9)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(20, 20), SizeF(7.1, 7.1)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(20, 20), SizeF(9, 6)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(20, 20), SizeF(2, 8)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(20, 20), SizeF(8, 2)));
+
+ // Bottom.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(10, 25), SizeF(20, 2)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(10, 25), SizeF(20, 4.9)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(10, 25), SizeF(20, 5.1)));
+
+ // Bottom-left.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(0, 20), SizeF(7, 7)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(0, 20), SizeF(6, 9)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(0, 20), SizeF(7.1, 7.1)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(0, 20), SizeF(9, 6)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(0, 20), SizeF(2, 8)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(0, 20), SizeF(8, 2)));
+
+ // Left.
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(-5, 10), SizeF(2, 20)));
+ EXPECT_FALSE(quad.IntersectsEllipse(PointF(-5, 10), SizeF(4.9, 20)));
+ EXPECT_TRUE(quad.IntersectsEllipse(PointF(-5, 10), SizeF(5.1, 20)));
+}
+
+TEST(QuadFTest, CircleIntersectionIsInclusive) {
+ // A rectilinear quad at (10, 10) with dimensions 10x10.
+ QuadF quad(RectF(10, 10, 10, 10));
+
+ // A circle fully contained in the top-left of the quad should intersect.
+ EXPECT_TRUE(quad.IntersectsCircle(PointF(12, 12), 1));
+
+ // A point fully contained in the top-left of the quad should intersect.
+ EXPECT_TRUE(quad.IntersectsCircle(PointF(12, 12), 0));
+
+ // A circle that touches the left edge should intersect.
+ EXPECT_TRUE(quad.IntersectsCircle(PointF(9, 11), 1));
+
+ // A circle that touches the top edge should intersect.
+ EXPECT_TRUE(quad.IntersectsCircle(PointF(11, 9), 1));
+
+ // A circle that touches the right edge should intersect.
+ EXPECT_TRUE(quad.IntersectsCircle(PointF(21, 11), 1));
+
+ // A circle that touches the bottom edge should intersect.
+ EXPECT_TRUE(quad.IntersectsCircle(PointF(11, 21), 1));
+
+ // A point that touches the left edge should intersect.
+ EXPECT_TRUE(quad.IntersectsCircle(PointF(10, 11), 0));
+
+ // A point that touches the top edge should intersect.
+ EXPECT_TRUE(quad.IntersectsCircle(PointF(11, 10), 0));
+
+ // A point that touches the right edge should intersect.
+ EXPECT_TRUE(quad.IntersectsCircle(PointF(20, 11), 0));
+
+ // A point that touches the bottom edge should intersect.
+ EXPECT_TRUE(quad.IntersectsCircle(PointF(11, 20), 0));
+
+ // A circle that is fully outside the quad should not intersect.
+ EXPECT_FALSE(quad.IntersectsCircle(PointF(9, 9), 1));
+
+ // A point that is fully outside the quad should not intersect.
+ EXPECT_FALSE(quad.IntersectsCircle(PointF(9, 9), 0));
+}
+
+TEST(QuadFTest, CenterPoint) {
+ EXPECT_EQ(PointF(), QuadF().CenterPoint());
+ EXPECT_EQ(PointF(25.75f, 40.75f),
+ QuadF(RectF(10.5f, 20.5f, 30.5f, 40.5f)).CenterPoint());
+ EXPECT_EQ(PointF(10, 10),
+ QuadF(PointF(10, 0), PointF(20, 10), PointF(10, 20), PointF(0, 10))
+ .CenterPoint());
+}
+
+} // namespace gfx
diff --git a/ui/gfx/geometry/quad_unittest.cc b/ui/gfx/geometry/quad_unittest.cc
deleted file mode 100644
index 87849b0..0000000
--- a/ui/gfx/geometry/quad_unittest.cc
+++ /dev/null
@@ -1,361 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <stddef.h>
-
-#include "base/cxx17_backports.h"
-#include "build/build_config.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/quad_f.h"
-#include "ui/gfx/geometry/rect_f.h"
-
-namespace gfx {
-
-TEST(QuadTest, Construction) {
- // Verify constructors.
- PointF a(1, 1);
- PointF b(2, 1);
- PointF c(2, 2);
- PointF d(1, 2);
- PointF e;
- QuadF q1;
- QuadF q2(e, e, e, e);
- QuadF q3(a, b, c, d);
- QuadF q4(BoundingRect(a, c));
- EXPECT_EQ(q1, q2);
- EXPECT_EQ(q3, q4);
-
- // Verify getters.
- EXPECT_EQ(q3.p1(), a);
- EXPECT_EQ(q3.p2(), b);
- EXPECT_EQ(q3.p3(), c);
- EXPECT_EQ(q3.p4(), d);
-
- // Verify setters.
- q3.set_p1(b);
- q3.set_p2(c);
- q3.set_p3(d);
- q3.set_p4(a);
- EXPECT_EQ(q3.p1(), b);
- EXPECT_EQ(q3.p2(), c);
- EXPECT_EQ(q3.p3(), d);
- EXPECT_EQ(q3.p4(), a);
-
- // Verify operator=(Rect)
- EXPECT_NE(q1, q4);
- q1 = BoundingRect(a, c);
- EXPECT_EQ(q1, q4);
-
- // Verify operator=(Quad)
- EXPECT_NE(q1, q3);
- q1 = q3;
- EXPECT_EQ(q1, q3);
-}
-
-TEST(QuadTest, AddingVectors) {
- PointF a(1, 1);
- PointF b(2, 1);
- PointF c(2, 2);
- PointF d(1, 2);
- Vector2dF v(3.5f, -2.5f);
-
- QuadF q1(a, b, c, d);
- QuadF added = q1 + v;
- q1 += v;
- QuadF expected1(PointF(4.5f, -1.5f),
- PointF(5.5f, -1.5f),
- PointF(5.5f, -0.5f),
- PointF(4.5f, -0.5f));
- EXPECT_EQ(expected1, added);
- EXPECT_EQ(expected1, q1);
-
- QuadF q2(a, b, c, d);
- QuadF subtracted = q2 - v;
- q2 -= v;
- QuadF expected2(PointF(-2.5f, 3.5f),
- PointF(-1.5f, 3.5f),
- PointF(-1.5f, 4.5f),
- PointF(-2.5f, 4.5f));
- EXPECT_EQ(expected2, subtracted);
- EXPECT_EQ(expected2, q2);
-
- QuadF q3(a, b, c, d);
- q3 += v;
- q3 -= v;
- EXPECT_EQ(QuadF(a, b, c, d), q3);
- EXPECT_EQ(q3, (q3 + v - v));
-}
-
-TEST(QuadTest, IsRectilinear) {
- PointF a(1, 1);
- PointF b(2, 1);
- PointF c(2, 2);
- PointF d(1, 2);
- Vector2dF v(3.5f, -2.5f);
-
- EXPECT_TRUE(QuadF().IsRectilinear());
- EXPECT_TRUE(QuadF(a, b, c, d).IsRectilinear());
- EXPECT_TRUE((QuadF(a, b, c, d) + v).IsRectilinear());
-
- float epsilon = std::numeric_limits<float>::epsilon();
- PointF a2(1 + epsilon / 2, 1 + epsilon / 2);
- PointF b2(2 + epsilon / 2, 1 + epsilon / 2);
- PointF c2(2 + epsilon / 2, 2 + epsilon / 2);
- PointF d2(1 + epsilon / 2, 2 + epsilon / 2);
- EXPECT_TRUE(QuadF(a2, b, c, d).IsRectilinear());
- EXPECT_TRUE((QuadF(a2, b, c, d) + v).IsRectilinear());
- EXPECT_TRUE(QuadF(a, b2, c, d).IsRectilinear());
- EXPECT_TRUE((QuadF(a, b2, c, d) + v).IsRectilinear());
- EXPECT_TRUE(QuadF(a, b, c2, d).IsRectilinear());
- EXPECT_TRUE((QuadF(a, b, c2, d) + v).IsRectilinear());
- EXPECT_TRUE(QuadF(a, b, c, d2).IsRectilinear());
- EXPECT_TRUE((QuadF(a, b, c, d2) + v).IsRectilinear());
-
- struct {
- PointF a_off, b_off, c_off, d_off;
- } tests[] = {
- {
- PointF(1, 1.00001f),
- PointF(2, 1.00001f),
- PointF(2, 2.00001f),
- PointF(1, 2.00001f)
- },
- {
- PointF(1.00001f, 1),
- PointF(2.00001f, 1),
- PointF(2.00001f, 2),
- PointF(1.00001f, 2)
- },
- {
- PointF(1.00001f, 1.00001f),
- PointF(2.00001f, 1.00001f),
- PointF(2.00001f, 2.00001f),
- PointF(1.00001f, 2.00001f)
- },
- {
- PointF(1, 0.99999f),
- PointF(2, 0.99999f),
- PointF(2, 1.99999f),
- PointF(1, 1.99999f)
- },
- {
- PointF(0.99999f, 1),
- PointF(1.99999f, 1),
- PointF(1.99999f, 2),
- PointF(0.99999f, 2)
- },
- {
- PointF(0.99999f, 0.99999f),
- PointF(1.99999f, 0.99999f),
- PointF(1.99999f, 1.99999f),
- PointF(0.99999f, 1.99999f)
- }
- };
-
- for (size_t i = 0; i < base::size(tests); ++i) {
- PointF a_off = tests[i].a_off;
- PointF b_off = tests[i].b_off;
- PointF c_off = tests[i].c_off;
- PointF d_off = tests[i].d_off;
-
- EXPECT_FALSE(QuadF(a_off, b, c, d).IsRectilinear());
- EXPECT_FALSE((QuadF(a_off, b, c, d) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a, b_off, c, d).IsRectilinear());
- EXPECT_FALSE((QuadF(a, b_off, c, d) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a, b, c_off, d).IsRectilinear());
- EXPECT_FALSE((QuadF(a, b, c_off, d) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a, b, c, d_off).IsRectilinear());
- EXPECT_FALSE((QuadF(a, b, c, d_off) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a_off, b, c_off, d).IsRectilinear());
- EXPECT_FALSE((QuadF(a_off, b, c_off, d) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a, b_off, c, d_off).IsRectilinear());
- EXPECT_FALSE((QuadF(a, b_off, c, d_off) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a, b_off, c_off, d_off).IsRectilinear());
- EXPECT_FALSE((QuadF(a, b_off, c_off, d_off) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a_off, b, c_off, d_off).IsRectilinear());
- EXPECT_FALSE((QuadF(a_off, b, c_off, d_off) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a_off, b_off, c, d_off).IsRectilinear());
- EXPECT_FALSE((QuadF(a_off, b_off, c, d_off) + v).IsRectilinear());
- EXPECT_FALSE(QuadF(a_off, b_off, c_off, d).IsRectilinear());
- EXPECT_FALSE((QuadF(a_off, b_off, c_off, d) + v).IsRectilinear());
- EXPECT_TRUE(QuadF(a_off, b_off, c_off, d_off).IsRectilinear());
- EXPECT_TRUE((QuadF(a_off, b_off, c_off, d_off) + v).IsRectilinear());
- }
-}
-
-TEST(QuadTest, IsCounterClockwise) {
- PointF a1(1, 1);
- PointF b1(2, 1);
- PointF c1(2, 2);
- PointF d1(1, 2);
- EXPECT_FALSE(QuadF(a1, b1, c1, d1).IsCounterClockwise());
- EXPECT_FALSE(QuadF(b1, c1, d1, a1).IsCounterClockwise());
- EXPECT_TRUE(QuadF(a1, d1, c1, b1).IsCounterClockwise());
- EXPECT_TRUE(QuadF(c1, b1, a1, d1).IsCounterClockwise());
-
- // Slightly more complicated quads should work just as easily.
- PointF a2(1.3f, 1.4f);
- PointF b2(-0.7f, 4.9f);
- PointF c2(1.8f, 6.2f);
- PointF d2(2.1f, 1.6f);
- EXPECT_TRUE(QuadF(a2, b2, c2, d2).IsCounterClockwise());
- EXPECT_TRUE(QuadF(b2, c2, d2, a2).IsCounterClockwise());
- EXPECT_FALSE(QuadF(a2, d2, c2, b2).IsCounterClockwise());
- EXPECT_FALSE(QuadF(c2, b2, a2, d2).IsCounterClockwise());
-
- // Quads with 3 collinear points should work correctly, too.
- PointF a3(0, 0);
- PointF b3(1, 0);
- PointF c3(2, 0);
- PointF d3(1, 1);
- EXPECT_FALSE(QuadF(a3, b3, c3, d3).IsCounterClockwise());
- EXPECT_FALSE(QuadF(b3, c3, d3, a3).IsCounterClockwise());
- EXPECT_TRUE(QuadF(a3, d3, c3, b3).IsCounterClockwise());
- // The next expectation in particular would fail for an implementation
- // that incorrectly uses only a cross product of the first 3 vertices.
- EXPECT_TRUE(QuadF(c3, b3, a3, d3).IsCounterClockwise());
-
- // Non-convex quads should work correctly, too.
- PointF a4(0, 0);
- PointF b4(1, 1);
- PointF c4(2, 0);
- PointF d4(1, 3);
- EXPECT_FALSE(QuadF(a4, b4, c4, d4).IsCounterClockwise());
- EXPECT_FALSE(QuadF(b4, c4, d4, a4).IsCounterClockwise());
- EXPECT_TRUE(QuadF(a4, d4, c4, b4).IsCounterClockwise());
- EXPECT_TRUE(QuadF(c4, b4, a4, d4).IsCounterClockwise());
-
- // A quad with huge coordinates should not fail this check due to
- // single-precision overflow.
- PointF a5(1e30f, 1e30f);
- PointF b5(1e35f, 1e30f);
- PointF c5(1e35f, 1e35f);
- PointF d5(1e30f, 1e35f);
- EXPECT_FALSE(QuadF(a5, b5, c5, d5).IsCounterClockwise());
- EXPECT_FALSE(QuadF(b5, c5, d5, a5).IsCounterClockwise());
- EXPECT_TRUE(QuadF(a5, d5, c5, b5).IsCounterClockwise());
- EXPECT_TRUE(QuadF(c5, b5, a5, d5).IsCounterClockwise());
-}
-
-TEST(QuadTest, BoundingBox) {
- RectF r(3.2f, 5.4f, 7.007f, 12.01f);
- EXPECT_EQ(r, QuadF(r).BoundingBox());
-
- PointF a(1.3f, 1.4f);
- PointF b(-0.7f, 4.9f);
- PointF c(1.8f, 6.2f);
- PointF d(2.1f, 1.6f);
- float left = -0.7f;
- float top = 1.4f;
- float right = 2.1f;
- float bottom = 6.2f;
- EXPECT_EQ(RectF(left, top, right - left, bottom - top),
- QuadF(a, b, c, d).BoundingBox());
-}
-
-TEST(QuadTest, ContainsPoint) {
- PointF a(1.3f, 1.4f);
- PointF b(-0.8f, 4.4f);
- PointF c(1.8f, 6.1f);
- PointF d(2.1f, 1.6f);
-
- Vector2dF epsilon_x(2 * std::numeric_limits<float>::epsilon(), 0);
- Vector2dF epsilon_y(0, 2 * std::numeric_limits<float>::epsilon());
-
- Vector2dF ac_center = c - a;
- ac_center.Scale(0.5f);
- Vector2dF bd_center = d - b;
- bd_center.Scale(0.5f);
-
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(a + ac_center));
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(b + bd_center));
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(c - ac_center));
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(d - bd_center));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - ac_center));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - bd_center));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + ac_center));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + bd_center));
-
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(a));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - epsilon_x));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(a - epsilon_y));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(a + epsilon_x));
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(a + epsilon_y));
-
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(b));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - epsilon_x));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(b - epsilon_y));
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(b + epsilon_x));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(b + epsilon_y));
-
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(c));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(c - epsilon_x));
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(c - epsilon_y));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + epsilon_x));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(c + epsilon_y));
-
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(d));
- EXPECT_TRUE(QuadF(a, b, c, d).Contains(d - epsilon_x));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(d - epsilon_y));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + epsilon_x));
- EXPECT_FALSE(QuadF(a, b, c, d).Contains(d + epsilon_y));
-
- // Test a simple square.
- PointF s1(-1, -1);
- PointF s2(1, -1);
- PointF s3(1, 1);
- PointF s4(-1, 1);
- // Top edge.
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, -1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0.0f, -1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.0f)));
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, -1.0f)));
- // Bottom edge.
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, 1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0.0f, 1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.0f)));
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, 1.0f)));
- // Left edge.
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.1f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, -1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 0.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.0f)));
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.0f, 1.1f)));
- // Right edge.
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.1f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, -1.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 0.0f)));
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.0f)));
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.0f, 1.1f)));
- // Centered inside.
- EXPECT_TRUE(QuadF(s1, s2, s3, s4).Contains(PointF(0, 0)));
- // Centered outside.
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(-1.1f, 0)));
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(1.1f, 0)));
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(0, -1.1f)));
- EXPECT_FALSE(QuadF(s1, s2, s3, s4).Contains(PointF(0, 1.1f)));
-}
-
-TEST(QuadTest, Scale) {
- PointF a(1.3f, 1.4f);
- PointF b(-0.8f, 4.4f);
- PointF c(1.8f, 6.1f);
- PointF d(2.1f, 1.6f);
- QuadF q1(a, b, c, d);
- q1.Scale(1.5f);
-
- PointF a_scaled = ScalePoint(a, 1.5f);
- PointF b_scaled = ScalePoint(b, 1.5f);
- PointF c_scaled = ScalePoint(c, 1.5f);
- PointF d_scaled = ScalePoint(d, 1.5f);
- EXPECT_EQ(q1, QuadF(a_scaled, b_scaled, c_scaled, d_scaled));
-
- QuadF q2;
- q2.Scale(1.5f);
- EXPECT_EQ(q2, q2);
-}
-
-} // namespace gfx
diff --git a/ui/gfx/geometry/quaternion.cc b/ui/gfx/geometry/quaternion.cc
index 86d674e..465c2d2 100644
--- a/ui/gfx/geometry/quaternion.cc
+++ b/ui/gfx/geometry/quaternion.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -26,7 +26,7 @@
return;
Vector3dF normalized = axis;
- normalized.Scale(1.0 / length);
+ normalized.InvScale(length);
theta *= 0.5;
double s = sin(theta);
diff --git a/ui/gfx/geometry/quaternion.h b/ui/gfx/geometry/quaternion.h
index 8081881..a7df65a 100644
--- a/ui/gfx/geometry/quaternion.h
+++ b/ui/gfx/geometry/quaternion.h
@@ -1,10 +1,11 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_GEOMETRY_QUATERNION_H_
#define UI_GFX_GEOMETRY_QUATERNION_H_
+#include <iosfwd>
#include <string>
#include "ui/gfx/geometry/geometry_export.h"
@@ -104,6 +105,11 @@
return !(lhs == rhs);
}
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const Quaternion& transform, ::std::ostream* os);
+
} // namespace gfx
#endif // UI_GFX_GEOMETRY_QUATERNION_H_
diff --git a/ui/gfx/geometry/quaternion_unittest.cc b/ui/gfx/geometry/quaternion_unittest.cc
index 3c9fd2b..e50fe10 100644
--- a/ui/gfx/geometry/quaternion_unittest.cc
+++ b/ui/gfx/geometry/quaternion_unittest.cc
@@ -1,13 +1,13 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/gfx/geometry/quaternion.h"
+
#include <cmath>
-#include "base/cxx17_backports.h"
#include "base/numerics/math_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/quaternion.h"
#include "ui/gfx/geometry/vector3d_f.h"
namespace gfx {
@@ -62,7 +62,7 @@
TEST(QuatTest, Addition) {
double values[] = {0, 1, 100};
- for (size_t i = 0; i < base::size(values); ++i) {
+ for (size_t i = 0; i < std::size(values); ++i) {
float t = values[i];
Quaternion a(t, 2 * t, 3 * t, 4 * t);
Quaternion b(5 * t, 4 * t, 3 * t, 2 * t);
@@ -87,7 +87,7 @@
Quaternion(32, 32, 56, -6)},
};
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
Quaternion product = cases[i].a * cases[i].b;
CompareQuaternions(cases[i].expected, product);
}
@@ -95,7 +95,7 @@
TEST(QuatTest, Scaling) {
double values[] = {0, 10, 100};
- for (size_t i = 0; i < base::size(values); ++i) {
+ for (size_t i = 0; i < std::size(values); ++i) {
double s = values[i];
Quaternion q(1, 2, 3, 4);
Quaternion expected(s, 2 * s, 3 * s, 4 * s);
diff --git a/ui/gfx/geometry/rect.cc b/ui/gfx/geometry/rect.cc
index 02b7156..9115473 100644
--- a/ui/gfx/geometry/rect.cc
+++ b/ui/gfx/geometry/rect.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,47 +6,22 @@
#include <algorithm>
-#if defined(OS_WIN)
-#include <windows.h>
-#elif defined(OS_IOS)
-#include <CoreGraphics/CoreGraphics.h>
-#elif defined(OS_MAC)
-#include <ApplicationServices/ApplicationServices.h>
-#endif
-
#include "base/check.h"
#include "base/numerics/clamped_math.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/outsets.h"
-namespace gfx {
-
-#if defined(OS_WIN)
-Rect::Rect(const RECT& r)
- : origin_(r.left, r.top),
- size_(std::abs(r.right - r.left), std::abs(r.bottom - r.top)) {
-}
-#elif defined(OS_APPLE)
-Rect::Rect(const CGRect& r)
- : origin_(r.origin.x, r.origin.y), size_(r.size.width, r.size.height) {
-}
+#if BUILDFLAG(IS_WIN)
+#include <windows.h>
+#elif BUILDFLAG(IS_IOS)
+#include <CoreGraphics/CoreGraphics.h>
+#elif BUILDFLAG(IS_MAC)
+#include <ApplicationServices/ApplicationServices.h>
#endif
-#if defined(OS_WIN)
-RECT Rect::ToRECT() const {
- RECT r;
- r.left = x();
- r.right = right();
- r.top = y();
- r.bottom = bottom();
- return r;
-}
-#elif defined(OS_APPLE)
-CGRect Rect::ToCGRect() const {
- return CGRectMake(x(), y(), width(), height());
-}
-#endif
+namespace {
void AdjustAlongAxis(int dst_origin, int dst_size, int* origin, int* size) {
*size = std::min(dst_size, *size);
@@ -56,13 +31,9 @@
*origin = std::min(dst_origin + dst_size, *origin + *size) - *size;
}
-} // namespace
-
-namespace gfx {
-
// This is the per-axis heuristic for picking the most useful origin and
// width/height to represent the input range.
-static void SaturatedClampRange(int min, int max, int* origin, int* span) {
+void SaturatedClampRange(int min, int max, int* origin, int* span) {
if (max < min) {
*span = 0;
*origin = min;
@@ -99,25 +70,54 @@
}
}
-void Rect::SetByBounds(int left, int top, int right, int bottom) {
- int x, y;
- int width, height;
- SaturatedClampRange(left, right, &x, &width);
- SaturatedClampRange(top, bottom, &y, &height);
- origin_.SetPoint(x, y);
- size_.SetSize(width, height);
+} // namespace
+
+namespace gfx {
+
+#if BUILDFLAG(IS_WIN)
+
+Rect::Rect(const RECT& r)
+ : origin_(r.left, r.top),
+ size_(std::abs(r.right - r.left), std::abs(r.bottom - r.top)) {}
+
+RECT Rect::ToRECT() const {
+ RECT r;
+ r.left = x();
+ r.right = right();
+ r.top = y();
+ r.bottom = bottom();
+ return r;
+}
+
+#elif BUILDFLAG(IS_APPLE)
+
+Rect::Rect(const CGRect& r)
+ : origin_(r.origin.x, r.origin.y), size_(r.size.width, r.size.height) {}
+
+CGRect Rect::ToCGRect() const {
+ return CGRectMake(x(), y(), width(), height());
+}
+
+#endif
+
+void Rect::AdjustForSaturatedRight(int right) {
+ int new_x, width;
+ SaturatedClampRange(x(), right, &new_x, &width);
+ set_x(new_x);
+ size_.set_width(width);
+}
+
+void Rect::AdjustForSaturatedBottom(int bottom) {
+ int new_y, height;
+ SaturatedClampRange(y(), bottom, &new_y, &height);
+ set_y(new_y);
+ size_.set_height(height);
}
void Rect::Inset(const Insets& insets) {
- Inset(insets.left(), insets.top(), insets.right(), insets.bottom());
-}
-
-void Rect::Inset(int left, int top, int right, int bottom) {
- origin_ += Vector2d(left, top);
- // left+right might overflow/underflow, but width() - (left+right) might
- // overflow as well.
- set_width(base::ClampSub(width(), base::ClampAdd(left, right)));
- set_height(base::ClampSub(height(), base::ClampAdd(top, bottom)));
+ origin_ += Vector2d(insets.left(), insets.top());
+ set_width(base::ClampSub(width(), insets.width()));
+ set_height(base::ClampSub(height(), insets.height()));
}
void Rect::Offset(const Vector2d& distance) {
@@ -127,22 +127,9 @@
set_height(height());
}
-void Rect::operator+=(const Vector2d& offset) {
- origin_ += offset;
- // Ensure that width and height remain valid.
- set_width(width());
- set_height(height());
-}
-
-void Rect::operator-=(const Vector2d& offset) {
- origin_ -= offset;
-}
-
Insets Rect::InsetsFrom(const Rect& inner) const {
- return Insets(inner.y() - y(),
- inner.x() - x(),
- bottom() - inner.bottom(),
- right() - inner.right());
+ return Insets::TLBR(inner.y() - y(), inner.x() - x(),
+ bottom() - inner.bottom(), right() - inner.right());
}
bool Rect::operator<(const Rect& other) const {
@@ -191,6 +178,22 @@
SetByBounds(left, top, new_right, new_bottom);
}
+bool Rect::InclusiveIntersect(const Rect& rect) {
+ int left = std::max(x(), rect.x());
+ int top = std::max(y(), rect.y());
+ int new_right = std::min(right(), rect.right());
+ int new_bottom = std::min(bottom(), rect.bottom());
+
+ // Return a clean empty rectangle for non-intersecting cases.
+ if (left > new_right || top > new_bottom) {
+ SetRect(0, 0, 0, 0);
+ return false;
+ }
+
+ SetByBounds(left, top, new_right, new_bottom);
+ return true;
+}
+
void Rect::Union(const Rect& rect) {
if (IsEmpty()) {
*this = rect;
@@ -199,6 +202,10 @@
if (rect.IsEmpty())
return;
+ UnionEvenIfEmpty(rect);
+}
+
+void Rect::UnionEvenIfEmpty(const Rect& rect) {
SetByBounds(std::min(x(), rect.x()), std::min(y(), rect.y()),
std::max(right(), rect.right()),
std::max(bottom(), rect.bottom()));
@@ -332,6 +339,12 @@
return result;
}
+Rect UnionRectsEvenIfEmpty(const Rect& a, const Rect& b) {
+ Rect result = a;
+ result.UnionEvenIfEmpty(b);
+ return result;
+}
+
Rect SubtractRects(const Rect& a, const Rect& b) {
Rect result = a;
result.Subtract(b);
@@ -345,4 +358,37 @@
return result;
}
+Rect MaximumCoveredRect(const Rect& a, const Rect& b) {
+ // Check a or b by itself.
+ Rect maximum = a;
+ uint64_t maximum_area = a.size().Area64();
+ if (b.size().Area64() > maximum_area) {
+ maximum = b;
+ maximum_area = b.size().Area64();
+ }
+ // Check the regions that include the intersection of a and b. This can be
+ // done by taking the intersection and expanding it vertically and
+ // horizontally. These expanded intersections will both still be covered by
+ // a or b.
+ Rect intersection = a;
+ intersection.InclusiveIntersect(b);
+ if (!intersection.size().IsZero()) {
+ Rect vert_expanded_intersection = intersection;
+ vert_expanded_intersection.SetVerticalBounds(
+ std::min(a.y(), b.y()), std::max(a.bottom(), b.bottom()));
+ if (vert_expanded_intersection.size().Area64() > maximum_area) {
+ maximum = vert_expanded_intersection;
+ maximum_area = vert_expanded_intersection.size().Area64();
+ }
+ Rect horiz_expanded_intersection = intersection;
+ horiz_expanded_intersection.SetHorizontalBounds(
+ std::min(a.x(), b.x()), std::max(a.right(), b.right()));
+ if (horiz_expanded_intersection.size().Area64() > maximum_area) {
+ maximum = horiz_expanded_intersection;
+ maximum_area = horiz_expanded_intersection.size().Area64();
+ }
+ }
+ return maximum;
+}
+
} // namespace gfx
diff --git a/ui/gfx/geometry/rect.h b/ui/gfx/geometry/rect.h
index c980174..4ce53df 100644
--- a/ui/gfx/geometry/rect.h
+++ b/ui/gfx/geometry/rect.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -16,37 +16,258 @@
#include <iosfwd>
#include <string>
+#include "base/check.h"
+#include "base/numerics/clamped_math.h"
+#include "base/numerics/safe_conversions.h"
+#include "build/build_config.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/outsets.h"
#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/rect_base.h"
-#include "ui/gfx/geometry/rect_base_impl.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/vector2d.h"
+#if BUILDFLAG(IS_WIN)
+typedef struct tagRECT RECT;
+#elif BUILDFLAG(IS_APPLE)
+typedef struct CGRect CGRect;
+#endif
+
namespace gfx {
-class Insets;
-
-class Rect : public RectBase<Rect, Point, Size, Insets, Vector2d, int> {
+class GEOMETRY_EXPORT Rect {
public:
- Rect() : RectBase<Rect, Point, Size, Insets, Vector2d, int>(Point()) {}
+ constexpr Rect() = default;
+ constexpr Rect(int width, int height) : size_(width, height) {}
+ constexpr Rect(int x, int y, int width, int height)
+ : origin_(x, y),
+ size_(ClampWidthOrHeight(x, width), ClampWidthOrHeight(y, height)) {}
+ constexpr explicit Rect(const Size& size) : size_(size) {}
+ constexpr Rect(const Point& origin, const Size& size)
+ : origin_(origin),
+ size_(ClampWidthOrHeight(origin.x(), size.width()),
+ ClampWidthOrHeight(origin.y(), size.height())) {}
- Rect(int width, int height)
- : RectBase<Rect, Point, Size, Insets, Vector2d, int>(
- Size(width, height)) {}
+#if BUILDFLAG(IS_WIN)
+ explicit Rect(const RECT& r);
+#elif BUILDFLAG(IS_APPLE)
+ explicit Rect(const CGRect& r);
+#endif
- Rect(int x, int y, int width, int height)
- : RectBase<Rect, Point, Size, Insets, Vector2d, int>(
- Point(x, y), Size(width, height)) {}
+#if BUILDFLAG(IS_WIN)
+ // Construct an equivalent Win32 RECT object.
+ RECT ToRECT() const;
+#elif BUILDFLAG(IS_APPLE)
+ // Construct an equivalent CoreGraphics object.
+ CGRect ToCGRect() const;
+#endif
- explicit Rect(const Size& size)
- : RectBase<Rect, Point, Size, Insets, Vector2d, int>(size) {}
+ constexpr int x() const { return origin_.x(); }
+ // Sets the X position while preserving the width.
+ void set_x(int x) {
+ origin_.set_x(x);
+ size_.set_width(ClampWidthOrHeight(x, width()));
+ }
- Rect(const Point& origin, const Size& size)
- : RectBase<Rect, Point, Size, Insets, Vector2d, int>(origin, size) {}
+ constexpr int y() const { return origin_.y(); }
+ // Sets the Y position while preserving the height.
+ void set_y(int y) {
+ origin_.set_y(y);
+ size_.set_height(ClampWidthOrHeight(y, height()));
+ }
- ~Rect() {}
+ constexpr int width() const { return size_.width(); }
+ void set_width(int width) { size_.set_width(ClampWidthOrHeight(x(), width)); }
+
+ constexpr int height() const { return size_.height(); }
+ void set_height(int height) {
+ size_.set_height(ClampWidthOrHeight(y(), height));
+ }
+
+ constexpr const Point& origin() const { return origin_; }
+ void set_origin(const Point& origin) {
+ origin_ = origin;
+ // Ensure that width and height remain valid.
+ set_width(width());
+ set_height(height());
+ }
+
+ constexpr const Size& size() const { return size_; }
+ void set_size(const Size& size) {
+ set_width(size.width());
+ set_height(size.height());
+ }
+
+ constexpr int right() const { return x() + width(); }
+ constexpr int bottom() const { return y() + height(); }
+
+ constexpr Point top_right() const { return Point(right(), y()); }
+ constexpr Point bottom_left() const { return Point(x(), bottom()); }
+ constexpr Point bottom_right() const { return Point(right(), bottom()); }
+
+ constexpr Point left_center() const { return Point(x(), y() + height() / 2); }
+ constexpr Point top_center() const { return Point(x() + width() / 2, y()); }
+ constexpr Point right_center() const {
+ return Point(right(), y() + height() / 2);
+ }
+ constexpr Point bottom_center() const {
+ return Point(x() + width() / 2, bottom());
+ }
+
+ Vector2d OffsetFromOrigin() const { return Vector2d(x(), y()); }
+
+ void SetRect(int x, int y, int width, int height) {
+ origin_.SetPoint(x, y);
+ // Ensure that width and height remain valid.
+ set_width(width);
+ set_height(height);
+ }
+
+ // Use in place of SetRect() when you know the edges of the rectangle instead
+ // of the dimensions, rather than trying to determine the width/height
+ // yourself. This safely handles cases where the width/height would overflow.
+ void SetByBounds(int left, int top, int right, int bottom) {
+ SetHorizontalBounds(left, right);
+ SetVerticalBounds(top, bottom);
+ }
+ void SetHorizontalBounds(int left, int right) {
+ set_x(left);
+ set_width(base::ClampSub(right, left));
+ if (UNLIKELY(this->right() != right))
+ AdjustForSaturatedRight(right);
+ }
+ void SetVerticalBounds(int top, int bottom) {
+ set_y(top);
+ set_height(base::ClampSub(bottom, top));
+ if (UNLIKELY(this->bottom() != bottom))
+ AdjustForSaturatedBottom(bottom);
+ }
+
+ // Shrink the rectangle by |inset| on all sides.
+ void Inset(int inset) { Inset(Insets(inset)); }
+ // Shrink the rectangle by the given |insets|.
+ void Inset(const Insets& insets);
+
+ // Expand the rectangle by |outset| on all sides.
+ void Outset(int outset) { Inset(-outset); }
+ // Expand the rectangle by the given |outsets|.
+ void Outset(const Outsets& outsets) { Inset(outsets.ToInsets()); }
+
+ // Move the rectangle by a horizontal and vertical distance.
+ void Offset(int horizontal, int vertical) {
+ Offset(Vector2d(horizontal, vertical));
+ }
+ void Offset(const Vector2d& distance);
+ void operator+=(const Vector2d& offset) { Offset(offset); }
+ void operator-=(const Vector2d& offset) { Offset(-offset); }
+
+ Insets InsetsFrom(const Rect& inner) const;
+
+ // Returns true if the area of the rectangle is zero.
+ bool IsEmpty() const { return size_.IsEmpty(); }
+
+ // A rect is less than another rect if its origin is less than
+ // the other rect's origin. If the origins are equal, then the
+ // shortest rect is less than the other. If the origin and the
+ // height are equal, then the narrowest rect is less than.
+ // This comparison is required to use Rects in sets, or sorted
+ // vectors.
+ bool operator<(const Rect& other) const;
+
+ // Returns true if the point identified by point_x and point_y falls inside
+ // this rectangle. The point (x, y) is inside the rectangle, but the
+ // point (x + width, y + height) is not.
+ bool Contains(int point_x, int point_y) const;
+
+ // Returns true if the specified point is contained by this rectangle.
+ bool Contains(const Point& point) const {
+ return Contains(point.x(), point.y());
+ }
+
+ // Returns true if this rectangle contains the specified rectangle.
+ bool Contains(const Rect& rect) const;
+
+ // Returns true if this rectangle intersects the specified rectangle.
+ // An empty rectangle doesn't intersect any rectangle.
+ bool Intersects(const Rect& rect) const;
+
+ // Sets this rect to be the intersection of this rectangle with the given
+ // rectangle.
+ void Intersect(const Rect& rect);
+
+ // Sets this rect to be the intersection of itself and |rect| using
+ // edge-inclusive geometry. If the two rectangles overlap but the overlap
+ // region is zero-area (either because one of the two rectangles is zero-area,
+ // or because the rectangles overlap at an edge or a corner), the result is
+ // the zero-area intersection. The return value indicates whether the two
+ // rectangle actually have an intersection, since checking the result for
+ // isEmpty() is not conclusive.
+ bool InclusiveIntersect(const Rect& rect);
+
+ // Sets this rect to be the union of this rectangle with the given rectangle.
+ // The union is the smallest rectangle containing both rectangles if not
+ // empty. If both rects are empty, this rect will become |rect|.
+ void Union(const Rect& rect);
+
+ // Similar to Union(), but the result will contain both rectangles even if
+ // either of them is empty. For example, union of (100, 100, 0x0) and
+ // (200, 200, 50x0) is (100, 100, 150x100).
+ void UnionEvenIfEmpty(const Rect& rect);
+
+ // Sets this rect to be the rectangle resulting from subtracting |rect| from
+ // |*this|, i.e. the bounding rect of |Region(*this) - Region(rect)|.
+ void Subtract(const Rect& rect);
+
+ // Fits as much of the receiving rectangle into the supplied rectangle as
+ // possible, becoming the result. For example, if the receiver had
+ // a x-location of 2 and a width of 4, and the supplied rectangle had
+ // an x-location of 0 with a width of 5, the returned rectangle would have
+ // an x-location of 1 with a width of 4.
+ void AdjustToFit(const Rect& rect);
+
+ // Returns the center of this rectangle.
+ Point CenterPoint() const;
+
+ // Becomes a rectangle that has the same center point but with a size capped
+ // at given |size|.
+ void ClampToCenteredSize(const Size& size);
+
+ // Transpose x and y axis.
+ void Transpose();
+
+ // Splits |this| in two halves, |left_half| and |right_half|.
+ void SplitVertically(Rect* left_half, Rect* right_half) const;
+
+ // Returns true if this rectangle shares an entire edge (i.e., same width or
+ // same height) with the given rectangle, and the rectangles do not overlap.
+ bool SharesEdgeWith(const Rect& rect) const;
+
+ // Returns the manhattan distance from the rect to the point. If the point is
+ // inside the rect, returns 0.
+ int ManhattanDistanceToPoint(const Point& point) const;
+
+ // Returns the manhattan distance between the contents of this rect and the
+ // contents of the given rect. That is, if the intersection of the two rects
+ // is non-empty then the function returns 0. If the rects share a side, it
+ // returns the smallest non-zero value appropriate for int.
+ int ManhattanInternalDistance(const Rect& rect) const;
std::string ToString() const;
+
+ bool ApproximatelyEqual(const Rect& rect, int tolerance) const;
+
+ private:
+ // Clamp the width/height to avoid integer overflow in bottom() and right().
+ // This returns the clamped width/height given an |x_or_y| and a
+ // |width_or_height|.
+ static constexpr int ClampWidthOrHeight(int x_or_y, int width_or_height) {
+ return base::ClampAdd(x_or_y, width_or_height) - x_or_y;
+ }
+
+ void AdjustForSaturatedRight(int right);
+ void AdjustForSaturatedBottom(int bottom);
+
+ gfx::Point origin_;
+ gfx::Size size_;
};
inline bool operator==(const Rect& lhs, const Rect& rhs) {
@@ -57,21 +278,17 @@
return !(lhs == rhs);
}
-Rect operator+(const Rect& lhs, const Vector2d& rhs);
-Rect operator-(const Rect& lhs, const Vector2d& rhs);
-
-inline std::ostream& operator<<(std::ostream& os, const Rect& rect) {
- os << rect.ToString();
- return os;
-}
+GEOMETRY_EXPORT Rect operator+(const Rect& lhs, const Vector2d& rhs);
+GEOMETRY_EXPORT Rect operator-(const Rect& lhs, const Vector2d& rhs);
inline Rect operator+(const Vector2d& lhs, const Rect& rhs) {
return rhs + lhs;
}
-Rect IntersectRects(const Rect& a, const Rect& b);
-Rect UnionRects(const Rect& a, const Rect& b);
-Rect SubtractRects(const Rect& a, const Rect& b);
+GEOMETRY_EXPORT Rect IntersectRects(const Rect& a, const Rect& b);
+GEOMETRY_EXPORT Rect UnionRects(const Rect& a, const Rect& b);
+GEOMETRY_EXPORT Rect UnionRectsEvenIfEmpty(const Rect& a, const Rect& b);
+GEOMETRY_EXPORT Rect SubtractRects(const Rect& a, const Rect& b);
// Constructs a rectangle with |p1| and |p2| as opposite corners.
//
@@ -79,43 +296,75 @@
// points", except that we consider points on the right/bottom edges of the
// rect to be outside the rect. So technically one or both points will not be
// contained within the rect, because they will appear on one of these edges.
-Rect BoundingRect(const Point& p1, const Point& p2);
+GEOMETRY_EXPORT Rect BoundingRect(const Point& p1, const Point& p2);
-inline Rect ScaleToEnclosingRect(const Rect& rect, float x_scale,
+// Scales the rect and returns the enclosing rect. The components are clamped
+// if they would overflow.
+inline Rect ScaleToEnclosingRect(const Rect& rect,
+ float x_scale,
float y_scale) {
- int x = static_cast<int>(std::floor(rect.x() * x_scale));
- int y = static_cast<int>(std::floor(rect.y() * y_scale));
- int r = rect.width() == 0
- ? x
- : static_cast<int>(std::ceil(rect.right() * x_scale));
- int b = rect.height() == 0
- ? y
- : static_cast<int>(std::ceil(rect.bottom() * y_scale));
- return Rect(x, y, r - x, b - y);
+ if (x_scale == 1.f && y_scale == 1.f)
+ return rect;
+ int x = base::ClampFloor(rect.x() * x_scale);
+ int y = base::ClampFloor(rect.y() * y_scale);
+ int r = rect.width() == 0 ? x : base::ClampCeil(rect.right() * x_scale);
+ int b = rect.height() == 0 ? y : base::ClampCeil(rect.bottom() * y_scale);
+ Rect result;
+ result.SetByBounds(x, y, r, b);
+ return result;
}
inline Rect ScaleToEnclosingRect(const Rect& rect, float scale) {
return ScaleToEnclosingRect(rect, scale, scale);
}
-inline Rect ScaleToEnclosedRect(const Rect& rect, float x_scale,
+inline Rect ScaleToEnclosedRect(const Rect& rect,
+ float x_scale,
float y_scale) {
- int x = static_cast<int>(std::ceil(rect.x() * x_scale));
- int y = static_cast<int>(std::ceil(rect.y() * y_scale));
- int r = rect.width() == 0
- ? x
- : static_cast<int>(std::floor(rect.right() * x_scale));
- int b = rect.height() == 0
- ? y
- : static_cast<int>(std::floor(rect.bottom() * y_scale));
- return Rect(x, y, r - x, b - y);
+ if (x_scale == 1.f && y_scale == 1.f)
+ return rect;
+ int x = base::ClampCeil(rect.x() * x_scale);
+ int y = base::ClampCeil(rect.y() * y_scale);
+ int r = rect.width() == 0 ? x : base::ClampFloor(rect.right() * x_scale);
+ int b = rect.height() == 0 ? y : base::ClampFloor(rect.bottom() * y_scale);
+ Rect result;
+ result.SetByBounds(x, y, r, b);
+ return result;
}
inline Rect ScaleToEnclosedRect(const Rect& rect, float scale) {
return ScaleToEnclosedRect(rect, scale, scale);
}
-// extern template class RectBase<Rect, Point, Size, Insets, Vector2d, int>;
+// Scales |rect| by scaling its four corner points. If the corner points lie on
+// non-integral coordinate after scaling, their values are rounded to the
+// nearest integer. The components are clamped if they would overflow.
+// This is helpful during layout when relative positions of multiple gfx::Rect
+// in a given coordinate space needs to be same after scaling as it was before
+// scaling. ie. this gives a lossless relative positioning of rects.
+inline Rect ScaleToRoundedRect(const Rect& rect, float x_scale, float y_scale) {
+ if (x_scale == 1.f && y_scale == 1.f)
+ return rect;
+ int x = base::ClampRound(rect.x() * x_scale);
+ int y = base::ClampRound(rect.y() * y_scale);
+ int r = rect.width() == 0 ? x : base::ClampRound(rect.right() * x_scale);
+ int b = rect.height() == 0 ? y : base::ClampRound(rect.bottom() * y_scale);
+ Rect result;
+ result.SetByBounds(x, y, r, b);
+ return result;
+}
+
+inline Rect ScaleToRoundedRect(const Rect& rect, float scale) {
+ return ScaleToRoundedRect(rect, scale, scale);
+}
+
+// Return a maximum rectangle that is covered by the a or b.
+GEOMETRY_EXPORT Rect MaximumCoveredRect(const Rect& a, const Rect& b);
+
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const Rect& rect, ::std::ostream* os);
} // namespace gfx
diff --git a/ui/gfx/geometry/rect_base.h b/ui/gfx/geometry/rect_base.h
deleted file mode 100644
index 0cec1ea..0000000
--- a/ui/gfx/geometry/rect_base.h
+++ /dev/null
@@ -1,173 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// A template for a simple rectangle class. The containment semantics
-// are array-like; that is, the coordinate (x, y) is considered to be
-// contained by the rectangle, but the coordinate (x + width, y) is not.
-// The class will happily let you create malformed rectangles (that is,
-// rectangles with negative width and/or height), but there will be assertions
-// in the operations (such as Contains()) to complain in this case.
-
-#ifndef UI_GFX_GEOMETRY_RECT_BASE_H_
-#define UI_GFX_GEOMETRY_RECT_BASE_H_
-
-#include <string>
-
-namespace gfx {
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-class RectBase {
- public:
- Type x() const { return origin_.x(); }
- void set_x(Type x) { origin_.set_x(x); }
-
- Type y() const { return origin_.y(); }
- void set_y(Type y) { origin_.set_y(y); }
-
- Type width() const { return size_.width(); }
- void set_width(Type width) { size_.set_width(width); }
-
- Type height() const { return size_.height(); }
- void set_height(Type height) { size_.set_height(height); }
-
- const PointClass& origin() const { return origin_; }
- void set_origin(const PointClass& origin) { origin_ = origin; }
-
- const SizeClass& size() const { return size_; }
- void set_size(const SizeClass& size) { size_ = size; }
-
- Type right() const { return x() + width(); }
- Type bottom() const { return y() + height(); }
-
- PointClass top_right() const { return PointClass(right(), y()); }
- PointClass bottom_left() const { return PointClass(x(), bottom()); }
- PointClass bottom_right() const { return PointClass(right(), bottom()); }
-
- VectorClass OffsetFromOrigin() const { return VectorClass(x(), y()); }
-
- void SetRect(Type x, Type y, Type width, Type height);
-
- // Shrink the rectangle by a horizontal and vertical distance on all sides.
- void Inset(Type horizontal, Type vertical) {
- Inset(horizontal, vertical, horizontal, vertical);
- }
-
- // Enlarge the rectangle by a horizontal and vertical distance on all sides.
- void Outset(Type horizontal, Type vertical) { Inset(-horizontal, -vertical); }
-
- // Shrink the rectangle by the given insets.
- void Inset(const InsetsClass& insets);
-
- // Enlarge the rectangle by the given insets.
- void Outset(const InsetsClass& insets) { Inset(-insets); }
-
- // Shrink the rectangle by the specified amount on each side.
- void Inset(Type left, Type top, Type right, Type bottom);
-
- // Enlarge the rectangle by the specified amount on each side.
- void Outset(Type left, Type top, Type right, Type bottom) {
- Inset(-left, -top, -right, -bottom);
- }
-
- // Move the rectangle by a horizontal and vertical distance.
- void Offset(Type horizontal, Type vertical);
- void Offset(const VectorClass& distance) {
- Offset(distance.x(), distance.y());
- }
- void operator+=(const VectorClass& offset);
- void operator-=(const VectorClass& offset);
-
- InsetsClass InsetsFrom(const Class& inner) const {
- return InsetsClass(inner.x() - x(), inner.y() - y(),
- right() - inner.right(), bottom() - inner.bottom());
- }
-
- // Returns true if the area of the rectangle is zero.
- bool IsEmpty() const { return size_.IsEmpty(); }
-
- // A rect is less than another rect if its origin is less than
- // the other rect's origin. If the origins are equal, then the
- // shortest rect is less than the other. If the origin and the
- // height are equal, then the narrowest rect is less than.
- // This comparison is required to use Rects in sets, or sorted
- // vectors.
- bool operator<(const Class& other) const;
-
- // Returns true if the point identified by point_x and point_y falls inside
- // this rectangle. The point (x, y) is inside the rectangle, but the
- // point (x + width, y + height) is not.
- bool Contains(Type point_x, Type point_y) const;
-
- // Returns true if the specified point is contained by this rectangle.
- bool Contains(const PointClass& point) const {
- return Contains(point.x(), point.y());
- }
-
- // Returns true if this rectangle contains the specified rectangle.
- bool Contains(const Class& rect) const;
-
- // Returns true if this rectangle intersects the specified rectangle.
- // An empty rectangle doesn't intersect any rectangle.
- bool Intersects(const Class& rect) const;
-
- // Computes the intersection of this rectangle with the given rectangle.
- void Intersect(const Class& rect);
-
- // Computes the union of this rectangle with the given rectangle. The union
- // is the smallest rectangle containing both rectangles.
- void Union(const Class& rect);
-
- // Computes the rectangle resulting from subtracting |rect| from |*this|,
- // i.e. the bounding rect of |Region(*this) - Region(rect)|.
- void Subtract(const Class& rect);
-
- // Fits as much of the receiving rectangle into the supplied rectangle as
- // possible, becoming the result. For example, if the receiver had
- // a x-location of 2 and a width of 4, and the supplied rectangle had
- // an x-location of 0 with a width of 5, the returned rectangle would have
- // an x-location of 1 with a width of 4.
- void AdjustToFit(const Class& rect);
-
- // Returns the center of this rectangle.
- PointClass CenterPoint() const;
-
- // Becomes a rectangle that has the same center point but with a size capped
- // at given |size|.
- void ClampToCenteredSize(const SizeClass& size);
-
- // Splits |this| in two halves, |left_half| and |right_half|.
- void SplitVertically(Class* left_half, Class* right_half) const;
-
- // Returns true if this rectangle shares an entire edge (i.e., same width or
- // same height) with the given rectangle, and the rectangles do not overlap.
- bool SharesEdgeWith(const Class& rect) const;
-
- // Returns the manhattan distance from the rect to the point. If the point is
- // inside the rect, returns 0.
- Type ManhattanDistanceToPoint(const PointClass& point) const;
-
- // Returns the manhattan distance between the contents of this rect and the
- // contents of the given rect. That is, if the intersection of the two rects
- // is non-empty then the function returns 0. If the rects share a side, it
- // returns the smallest non-zero value appropriate for Type.
- Type ManhattanInternalDistance(const Class& rect) const;
-
- protected:
- RectBase(const PointClass& origin, const SizeClass& size)
- : origin_(origin), size_(size) {}
- explicit RectBase(const SizeClass& size) : size_(size) {}
- explicit RectBase(const PointClass& origin) : origin_(origin) {}
- // Destructor is intentionally made non virtual and protected.
- // Do not make this public.
- ~RectBase() {}
-
- private:
- PointClass origin_;
- SizeClass size_;
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_GEOMETRY_RECT_BASE_H_
diff --git a/ui/gfx/geometry/rect_base_impl.h b/ui/gfx/geometry/rect_base_impl.h
deleted file mode 100644
index 09ee7f3..0000000
--- a/ui/gfx/geometry/rect_base_impl.h
+++ /dev/null
@@ -1,267 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_GEOMETRY_RECT_BASE_IMPL_H_
-#define UI_GFX_GEOMETRY_RECT_BASE_IMPL_H_
-
-#include <algorithm>
-#include <limits>
-
-#include "base/logging.h"
-#include "base/strings/stringprintf.h"
-#include "ui/gfx/geometry/rect_base.h"
-
-namespace gfx {
-
-template <typename Type>
-void AdjustAlongAxis(Type dst_origin, Type dst_size, Type* origin, Type* size) {
- *size = std::min(dst_size, *size);
- if (*origin < dst_origin)
- *origin = dst_origin;
- else
- *origin = std::min(dst_origin + dst_size, *origin + *size) - *size;
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::SetRect(Type x, Type y, Type width, Type height) {
- origin_.SetPoint(x, y);
- set_width(width);
- set_height(height);
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::Inset(const InsetsClass& insets) {
- Inset(insets.left(), insets.top(), insets.right(), insets.bottom());
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::Inset(Type left, Type top, Type right, Type bottom) {
- origin_ += VectorClass(left, top);
- set_width(std::max(width() - left - right, static_cast<Type>(0)));
- set_height(std::max(height() - top - bottom, static_cast<Type>(0)));
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::Offset(Type horizontal, Type vertical) {
- origin_ += VectorClass(horizontal, vertical);
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
-operator+=(const VectorClass& offset) {
- origin_ += offset;
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
-operator-=(const VectorClass& offset) {
- origin_ -= offset;
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>::
-operator<(const Class& other) const {
- if (origin_ == other.origin_) {
- if (width() == other.width()) {
- return height() < other.height();
- } else {
- return width() < other.width();
- }
- } else {
- return origin_ < other.origin_;
- }
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::Contains(Type point_x, Type point_y) const {
- return (point_x >= x()) && (point_x < right()) && (point_y >= y()) &&
- (point_y < bottom());
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::Contains(const Class& rect) const {
- return (rect.x() >= x() && rect.right() <= right() && rect.y() >= y() &&
- rect.bottom() <= bottom());
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::Intersects(const Class& rect) const {
- return !(IsEmpty() || rect.IsEmpty() || rect.x() >= right() ||
- rect.right() <= x() || rect.y() >= bottom() || rect.bottom() <= y());
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::Intersect(const Class& rect) {
- if (IsEmpty() || rect.IsEmpty()) {
- SetRect(Type(0), Type(0), Type(0), Type(0));
- return;
- }
-
- Type rx = std::max(x(), rect.x());
- Type ry = std::max(y(), rect.y());
- Type rr = std::min(right(), rect.right());
- Type rb = std::min(bottom(), rect.bottom());
-
- if (rx >= rr || ry >= rb) rx = ry = rr = rb = Type(0); // non-intersecting
-
- SetRect(rx, ry, rr - rx, rb - ry);
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::Union(const Class& rect) {
- if (IsEmpty()) {
- *this = rect;
- return;
- }
- if (rect.IsEmpty()) return;
-
- Type rx = std::min(x(), rect.x());
- Type ry = std::min(y(), rect.y());
- Type rr = std::max(right(), rect.right());
- Type rb = std::max(bottom(), rect.bottom());
-
- SetRect(rx, ry, rr - rx, rb - ry);
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::Subtract(const Class& rect) {
- if (!Intersects(rect)) return;
- if (rect.Contains(*static_cast<const Class*>(this))) {
- SetRect(Type(0), Type(0), Type(0), Type(0));
- return;
- }
-
- Type rx = x();
- Type ry = y();
- Type rr = right();
- Type rb = bottom();
-
- if (rect.y() <= y() && rect.bottom() >= bottom()) {
- // complete intersection in the y-direction
- if (rect.x() <= x()) {
- rx = rect.right();
- } else if (rect.right() >= right()) {
- rr = rect.x();
- }
- } else if (rect.x() <= x() && rect.right() >= right()) {
- // complete intersection in the x-direction
- if (rect.y() <= y()) {
- ry = rect.bottom();
- } else if (rect.bottom() >= bottom()) {
- rb = rect.y();
- }
- }
- SetRect(rx, ry, rr - rx, rb - ry);
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::AdjustToFit(const Class& rect) {
- Type new_x = x();
- Type new_y = y();
- Type new_width = width();
- Type new_height = height();
- AdjustAlongAxis(rect.x(), rect.width(), &new_x, &new_width);
- AdjustAlongAxis(rect.y(), rect.height(), &new_y, &new_height);
- SetRect(new_x, new_y, new_width, new_height);
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-PointClass RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::CenterPoint() const {
- return PointClass(x() + width() / 2, y() + height() / 2);
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::ClampToCenteredSize(const SizeClass& size) {
- Type new_width = std::min(width(), size.width());
- Type new_height = std::min(height(), size.height());
- Type new_x = x() + (width() - new_width) / 2;
- Type new_y = y() + (height() - new_height) / 2;
- SetRect(new_x, new_y, new_width, new_height);
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-void RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::SplitVertically(Class* left_half,
- Class* right_half) const {
- DCHECK(left_half);
- DCHECK(right_half);
-
- left_half->SetRect(x(), y(), width() / 2, height());
- right_half->SetRect(left_half->right(), y(), width() - left_half->width(),
- height());
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::SharesEdgeWith(const Class& rect) const {
- return (y() == rect.y() && height() == rect.height() &&
- (x() == rect.right() || right() == rect.x())) ||
- (x() == rect.x() && width() == rect.width() &&
- (y() == rect.bottom() || bottom() == rect.y()));
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-Type RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::ManhattanDistanceToPoint(const PointClass& point) const {
- Type x_distance =
- std::max<Type>(Type(0), std::max(x() - point.x(), point.x() - right()));
- Type y_distance =
- std::max<Type>(Type(0), std::max(y() - point.y(), point.y() - bottom()));
-
- return x_distance + y_distance;
-}
-
-template <typename Class, typename PointClass, typename SizeClass,
- typename InsetsClass, typename VectorClass, typename Type>
-Type RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass,
- Type>::ManhattanInternalDistance(const Class& rect) const {
- Class c(x(), y(), width(), height());
- c.Union(rect);
-
- const Type kEpsilon = std::numeric_limits<Type>::is_integer
- ? Type(1)
- : std::numeric_limits<Type>::epsilon();
-
- Type x =
- std::max<Type>(Type(0), c.width() - width() - rect.width() + kEpsilon);
- Type y =
- std::max<Type>(Type(0), c.height() - height() - rect.height() + kEpsilon);
- return x + y;
-}
-
-} // namespace gfx
-
-#endif // UI_GFX_GEOMETRY_RECT_BASE_IMPL_H_
diff --git a/ui/gfx/geometry/rect_conversions.cc b/ui/gfx/geometry/rect_conversions.cc
index 212318b..a5b1b96 100644
--- a/ui/gfx/geometry/rect_conversions.cc
+++ b/ui/gfx/geometry/rect_conversions.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/rect_conversions.h b/ui/gfx/geometry/rect_conversions.h
index 3460dcc..8ac6907 100644
--- a/ui/gfx/geometry/rect_conversions.h
+++ b/ui/gfx/geometry/rect_conversions.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,7 +10,9 @@
namespace gfx {
-// Returns the smallest Rect that encloses the given RectF.
+// Returns the smallest Rect that encloses the given RectF if possible.
+// The returned Rect is larger than or equal to the input RectF, unless the
+// the geometry values exceed int range and are clamped to int.
GEOMETRY_EXPORT Rect ToEnclosingRect(const RectF& rect);
// Similar to ToEnclosingRect(), but for each edge, if the distance between the
@@ -21,7 +23,10 @@
GEOMETRY_EXPORT Rect ToEnclosingRectIgnoringError(const RectF& rect,
float error);
-// Returns the largest Rect that is enclosed by the given RectF.
+// Returns the largest Rect that is enclosed by the given RectF if possible.
+// The returned rect is smaller than or equal to the input rect, but if
+// the input RectF is too small and no enclosed Rect exists, the returned
+// rect is an empty Rect at |ToCeiledPoint(rect.origin())|.
GEOMETRY_EXPORT Rect ToEnclosedRect(const RectF& rect);
// Similar to ToEnclosedRect(), but for each edge, if the distance between the
diff --git a/ui/gfx/geometry/rect_conversions_unittest.cc b/ui/gfx/geometry/rect_conversions_unittest.cc
new file mode 100644
index 0000000..9125851
--- /dev/null
+++ b/ui/gfx/geometry/rect_conversions_unittest.cc
@@ -0,0 +1,161 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/rect_conversions.h"
+
+#include <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gfx {
+
+constexpr int kMaxInt = std::numeric_limits<int>::max();
+constexpr int kMinInt = std::numeric_limits<int>::min();
+constexpr float kMaxFloat = std::numeric_limits<float>::max();
+constexpr float kEpsilonFloat = std::numeric_limits<float>::epsilon();
+constexpr float kMaxIntF = static_cast<float>(kMaxInt);
+constexpr float kMinIntF = static_cast<float>(kMinInt);
+
+TEST(RectConversionsTest, ToEnclosedRect) {
+ EXPECT_EQ(Rect(), ToEnclosedRect(RectF()));
+ EXPECT_EQ(Rect(-1, -1, 2, 2),
+ ToEnclosedRect(RectF(-1.5f, -1.5f, 3.0f, 3.0f)));
+ EXPECT_EQ(Rect(-1, -1, 3, 3),
+ ToEnclosedRect(RectF(-1.5f, -1.5f, 3.5f, 3.5f)));
+ EXPECT_EQ(Rect(kMaxInt, kMaxInt, 0, 0),
+ ToEnclosedRect(RectF(kMaxFloat, kMaxFloat, 2.0f, 2.0f)));
+ EXPECT_EQ(Rect(0, 0, kMaxInt, kMaxInt),
+ ToEnclosedRect(RectF(0.0f, 0.0f, kMaxFloat, kMaxFloat)));
+ EXPECT_EQ(Rect(20001, 20001, 0, 0),
+ ToEnclosedRect(RectF(20000.5f, 20000.5f, 0.5f, 0.5f)));
+ EXPECT_EQ(Rect(kMaxInt, kMaxInt, 0, 0),
+ ToEnclosedRect(RectF(kMaxIntF, kMaxIntF, kMaxIntF, kMaxIntF)));
+ EXPECT_EQ(Rect(2, 3, 5, 5),
+ ToEnclosedRect(RectF(1.9999f, 2.0002f, 5.9998f, 6.0001f)));
+ EXPECT_EQ(Rect(2, 3, 6, 4),
+ ToEnclosedRect(RectF(1.9999f, 2.0001f, 6.0002f, 5.9998f)));
+ EXPECT_EQ(Rect(2, 3, 5, 5),
+ ToEnclosedRect(RectF(1.9998f, 2.0002f, 6.0001f, 5.9999f)));
+}
+
+TEST(RectConversionsTest, ToEnclosedRectHugeRectF) {
+ RectF source(kMinIntF, kMinIntF, kMaxIntF * 3.f, kMaxIntF * 3.f);
+ Rect enclosed = ToEnclosedRect(source);
+
+ // That rect can't be represented, but it should be big.
+ EXPECT_EQ(kMaxInt, enclosed.width());
+ EXPECT_EQ(kMaxInt, enclosed.height());
+ // It should include some axis near the global origin.
+ EXPECT_GT(1, enclosed.x());
+ EXPECT_GT(1, enclosed.y());
+ // And it should not cause computation issues for itself.
+ EXPECT_LT(0, enclosed.right());
+ EXPECT_LT(0, enclosed.bottom());
+}
+
+TEST(RectConversionsTest, ToEnclosingRect) {
+ EXPECT_EQ(Rect(), ToEnclosingRect(RectF()));
+ EXPECT_EQ(Rect(5, 5, 0, 0), ToEnclosingRect(RectF(5.5f, 5.5f, 0.0f, 0.0f)));
+ EXPECT_EQ(Rect(3, 2, 0, 0),
+ ToEnclosingRect(RectF(3.5f, 2.5f, kEpsilonFloat, -0.0f)));
+ EXPECT_EQ(Rect(3, 2, 0, 1), ToEnclosingRect(RectF(3.5f, 2.5f, 0.f, 0.001f)));
+ EXPECT_EQ(Rect(-2, -2, 4, 4),
+ ToEnclosingRect(RectF(-1.5f, -1.5f, 3.0f, 3.0f)));
+ EXPECT_EQ(Rect(-2, -2, 4, 4),
+ ToEnclosingRect(RectF(-1.5f, -1.5f, 3.5f, 3.5f)));
+ EXPECT_EQ(Rect(kMaxInt, kMaxInt, 0, 0),
+ ToEnclosingRect(RectF(kMaxFloat, kMaxFloat, 2.0f, 2.0f)));
+ EXPECT_EQ(Rect(0, 0, kMaxInt, kMaxInt),
+ ToEnclosingRect(RectF(0.0f, 0.0f, kMaxFloat, kMaxFloat)));
+ EXPECT_EQ(Rect(20000, 20000, 1, 1),
+ ToEnclosingRect(RectF(20000.5f, 20000.5f, 0.5f, 0.5f)));
+ EXPECT_EQ(Rect(kMaxInt, kMaxInt, 0, 0),
+ ToEnclosingRect(RectF(kMaxIntF, kMaxIntF, kMaxIntF, kMaxIntF)));
+ EXPECT_EQ(Rect(-1, -1, 22777713, 2),
+ ToEnclosingRect(RectF(-0.5f, -0.5f, 22777712.f, 1.f)));
+ EXPECT_EQ(Rect(1, 2, 7, 7),
+ ToEnclosingRect(RectF(1.9999f, 2.0002f, 5.9998f, 6.0001f)));
+ EXPECT_EQ(Rect(1, 2, 8, 6),
+ ToEnclosingRect(RectF(1.9999f, 2.0001f, 6.0002f, 5.9998f)));
+ EXPECT_EQ(Rect(1, 2, 7, 7),
+ ToEnclosingRect(RectF(1.9998f, 2.0002f, 6.0001f, 5.9999f)));
+}
+
+TEST(RectConversionsTest, ToEnclosingRectHugeRectF) {
+ RectF source(kMinIntF, kMinIntF, kMaxIntF * 3.f, kMaxIntF * 3.f);
+ Rect enclosing = ToEnclosingRect(source);
+
+ // That rect can't be represented, but it should be big.
+ EXPECT_EQ(kMaxInt, enclosing.width());
+ EXPECT_EQ(kMaxInt, enclosing.height());
+ // It should include some axis near the global origin.
+ EXPECT_GT(1, enclosing.x());
+ EXPECT_GT(1, enclosing.y());
+ // And it should cause computation issues for itself.
+ EXPECT_LT(0, enclosing.right());
+ EXPECT_LT(0, enclosing.bottom());
+}
+
+TEST(RectConversionsTest, ToEnclosingRectIgnoringError) {
+ static constexpr float kError = 0.001f;
+ EXPECT_EQ(Rect(), ToEnclosingRectIgnoringError(RectF(), kError));
+ EXPECT_EQ(Rect(5, 5, 0, 0), ToEnclosingRectIgnoringError(
+ RectF(5.5f, 5.5f, 0.0f, 0.0f), kError));
+ EXPECT_EQ(Rect(3, 2, 0, 0),
+ ToEnclosingRectIgnoringError(
+ RectF(3.5f, 2.5f, kEpsilonFloat, -0.0f), kError));
+ EXPECT_EQ(Rect(3, 2, 0, 1), ToEnclosingRectIgnoringError(
+ RectF(3.5f, 2.5f, 0.f, 0.001f), kError));
+ EXPECT_EQ(Rect(-2, -2, 4, 4), ToEnclosingRectIgnoringError(
+ RectF(-1.5f, -1.5f, 3.0f, 3.0f), kError));
+ EXPECT_EQ(Rect(-2, -2, 4, 4), ToEnclosingRectIgnoringError(
+ RectF(-1.5f, -1.5f, 3.5f, 3.5f), kError));
+ EXPECT_EQ(Rect(kMaxInt, kMaxInt, 0, 0),
+ ToEnclosingRectIgnoringError(
+ RectF(kMaxFloat, kMaxFloat, 2.0f, 2.0f), kError));
+ EXPECT_EQ(Rect(0, 0, kMaxInt, kMaxInt),
+ ToEnclosingRectIgnoringError(
+ RectF(0.0f, 0.0f, kMaxFloat, kMaxFloat), kError));
+ EXPECT_EQ(Rect(20000, 20000, 1, 1),
+ ToEnclosingRectIgnoringError(RectF(20000.5f, 20000.5f, 0.5f, 0.5f),
+ kError));
+ EXPECT_EQ(Rect(kMaxInt, kMaxInt, 0, 0),
+ ToEnclosingRectIgnoringError(
+ RectF(kMaxIntF, kMaxIntF, kMaxIntF, kMaxIntF), kError));
+ EXPECT_EQ(Rect(-1, -1, 22777713, 2),
+ ToEnclosingRectIgnoringError(RectF(-0.5f, -0.5f, 22777712.f, 1.f),
+ kError));
+ EXPECT_EQ(Rect(2, 2, 6, 6),
+ ToEnclosingRectIgnoringError(
+ RectF(1.9999f, 2.0002f, 5.9998f, 6.0001f), kError));
+ EXPECT_EQ(Rect(2, 2, 6, 6),
+ ToEnclosingRectIgnoringError(
+ RectF(1.9999f, 2.0001f, 6.0002f, 5.9998f), kError));
+ EXPECT_EQ(Rect(2, 2, 6, 6),
+ ToEnclosingRectIgnoringError(
+ RectF(1.9998f, 2.0002f, 6.0001f, 5.9999f), kError));
+}
+
+TEST(RectConversionsTest, ToNearestRect) {
+ Rect rect;
+ EXPECT_EQ(rect, ToNearestRect(RectF(rect)));
+
+ rect = Rect(-1, -1, 3, 3);
+ EXPECT_EQ(rect, ToNearestRect(RectF(rect)));
+
+ RectF rectf(-1.00001f, -0.999999f, 3.0000001f, 2.999999f);
+ EXPECT_EQ(rect, ToNearestRect(rectf));
+}
+
+TEST(RectConversionsTest, ToFlooredRect) {
+ EXPECT_EQ(Rect(), ToFlooredRectDeprecated(RectF()));
+ EXPECT_EQ(Rect(-2, -2, 3, 3),
+ ToFlooredRectDeprecated(RectF(-1.5f, -1.5f, 3.0f, 3.0f)));
+ EXPECT_EQ(Rect(-2, -2, 3, 3),
+ ToFlooredRectDeprecated(RectF(-1.5f, -1.5f, 3.5f, 3.5f)));
+ EXPECT_EQ(Rect(20000, 20000, 0, 0),
+ ToFlooredRectDeprecated(RectF(20000.5f, 20000.5f, 0.5f, 0.5f)));
+}
+
+} // namespace gfx
diff --git a/ui/gfx/geometry/rect_f.cc b/ui/gfx/geometry/rect_f.cc
index c8dafe2..aa838f5 100644
--- a/ui/gfx/geometry/rect_f.cc
+++ b/ui/gfx/geometry/rect_f.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,14 +8,16 @@
#include <limits>
#include "base/check.h"
+#include "base/check_op.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "ui/gfx/geometry/insets_f.h"
+#include "ui/gfx/geometry/outsets_f.h"
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include <CoreGraphics/CoreGraphics.h>
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
#include <ApplicationServices/ApplicationServices.h>
#endif
@@ -32,7 +34,7 @@
*origin = std::min(dst_origin + dst_size, *origin + *size) - *size;
}
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
RectF::RectF(const CGRect& r)
: origin_(r.origin.x, r.origin.y), size_(r.size.width, r.size.height) {
}
@@ -43,13 +45,9 @@
#endif
void RectF::Inset(const InsetsF& insets) {
- Inset(insets.left(), insets.top(), insets.right(), insets.bottom());
-}
-
-void RectF::Inset(float left, float top, float right, float bottom) {
- origin_ += Vector2dF(left, top);
- set_width(std::max(width() - left - right, 0.0f));
- set_height(std::max(height() - top - bottom, 0.0f));
+ origin_ += Vector2dF(insets.left(), insets.top());
+ set_width(width() - insets.width());
+ set_height(height() - insets.height());
}
void RectF::Offset(float horizontal, float vertical) {
@@ -65,10 +63,8 @@
}
InsetsF RectF::InsetsFrom(const RectF& inner) const {
- return InsetsF(inner.y() - y(),
- inner.x() - x(),
- bottom() - inner.bottom(),
- right() - inner.right());
+ return InsetsF::TLBR(inner.y() - y(), inner.x() - x(),
+ bottom() - inner.bottom(), right() - inner.right());
}
bool RectF::operator<(const RectF& other) const {
@@ -85,6 +81,11 @@
point_y < bottom();
}
+bool RectF::InclusiveContains(float point_x, float point_y) const {
+ return point_x >= x() && point_x <= right() && point_y >= y() &&
+ point_y <= bottom();
+}
+
bool RectF::Contains(const RectF& rect) const {
return rect.x() >= x() && rect.right() <= right() && rect.y() >= y() &&
rect.bottom() <= bottom();
@@ -114,6 +115,22 @@
SetRect(rx, ry, rr - rx, rb - ry);
}
+bool RectF::InclusiveIntersect(const RectF& rect) {
+ float rx = std::max(x(), rect.x());
+ float ry = std::max(y(), rect.y());
+ float rr = std::min(right(), rect.right());
+ float rb = std::min(bottom(), rect.bottom());
+
+ // Return a clean empty rectangle for non-intersecting cases.
+ if (rx > rr || ry > rb) {
+ SetRect(0, 0, 0, 0);
+ return false;
+ }
+
+ SetRect(rx, ry, rr - rx, rb - ry);
+ return true;
+}
+
void RectF::Union(const RectF& rect) {
if (IsEmpty()) {
*this = rect;
@@ -122,12 +139,29 @@
if (rect.IsEmpty())
return;
+ UnionEvenIfEmpty(rect);
+}
+
+void RectF::UnionEvenIfEmpty(const RectF& rect) {
float rx = std::min(x(), rect.x());
float ry = std::min(y(), rect.y());
float rr = std::max(right(), rect.right());
float rb = std::max(bottom(), rect.bottom());
SetRect(rx, ry, rr - rx, rb - ry);
+
+ // Due to floating errors and SizeF::clamp(), the new rect may not fully
+ // contain the original rects at the right/bottom side. Expand the rect in
+ // the case.
+ constexpr auto kFloatMax = std::numeric_limits<float>::max();
+ if (UNLIKELY(right() < rr && width() < kFloatMax)) {
+ size_.SetToNextWidth();
+ DCHECK_GE(right(), rr);
+ }
+ if (UNLIKELY(bottom() < rb && height() < kFloatMax)) {
+ size_.SetToNextHeight();
+ DCHECK_GE(bottom(), rb);
+ }
}
void RectF::Subtract(const RectF& rect) {
@@ -222,6 +256,11 @@
return x + y;
}
+PointF RectF::ClosestPoint(const PointF& point) const {
+ return PointF(std::min(std::max(point.x(), x()), right()),
+ std::min(std::max(point.y(), y()), bottom()));
+}
+
bool RectF::IsExpressibleAsRect() const {
return base::IsValueInRangeForNumericType<int>(x()) &&
base::IsValueInRangeForNumericType<int>(y()) &&
@@ -231,12 +270,6 @@
base::IsValueInRangeForNumericType<int>(bottom());
}
-std::string RectF::ToString() const {
- return base::StringPrintf("%s %s",
- origin().ToString().c_str(),
- size().ToString().c_str());
-}
-
RectF IntersectRects(const RectF& a, const RectF& b) {
RectF result = a;
result.Intersect(b);
@@ -249,6 +282,12 @@
return result;
}
+RectF UnionRectsEvenIfEmpty(const RectF& a, const RectF& b) {
+ RectF result = a;
+ result.UnionEvenIfEmpty(b);
+ return result;
+}
+
RectF SubtractRects(const RectF& a, const RectF& b) {
RectF result = a;
result.Subtract(b);
@@ -263,4 +302,64 @@
return RectF(rx, ry, rr - rx, rb - ry);
}
+RectF MaximumCoveredRect(const RectF& a, const RectF& b) {
+ // Check a or b by itself.
+ RectF maximum = a;
+ float maximum_area = a.size().GetArea();
+ if (b.size().GetArea() > maximum_area) {
+ maximum = b;
+ maximum_area = b.size().GetArea();
+ }
+ // Check the regions that include the intersection of a and b. This can be
+ // done by taking the intersection and expanding it vertically and
+ // horizontally. These expanded intersections will both still be covered by
+ // a or b.
+ RectF intersection = a;
+ intersection.InclusiveIntersect(b);
+ if (!intersection.size().IsZero()) {
+ RectF vert_expanded_intersection = intersection;
+ vert_expanded_intersection.set_y(std::min(a.y(), b.y()));
+ vert_expanded_intersection.set_height(std::max(a.bottom(), b.bottom()) -
+ vert_expanded_intersection.y());
+ if (vert_expanded_intersection.size().GetArea() > maximum_area) {
+ maximum = vert_expanded_intersection;
+ maximum_area = vert_expanded_intersection.size().GetArea();
+ }
+ RectF horiz_expanded_intersection(intersection);
+ horiz_expanded_intersection.set_x(std::min(a.x(), b.x()));
+ horiz_expanded_intersection.set_width(std::max(a.right(), b.right()) -
+ horiz_expanded_intersection.x());
+ if (horiz_expanded_intersection.size().GetArea() > maximum_area) {
+ maximum = horiz_expanded_intersection;
+ maximum_area = horiz_expanded_intersection.size().GetArea();
+ }
+ }
+ return maximum;
+}
+
+RectF MapRect(const RectF& r, const RectF& src_rect, const RectF& dest_rect) {
+ if (src_rect.IsEmpty())
+ return RectF();
+
+ float width_scale = dest_rect.width() / src_rect.width();
+ float height_scale = dest_rect.height() / src_rect.height();
+ return RectF(dest_rect.x() + (r.x() - src_rect.x()) * width_scale,
+ dest_rect.y() + (r.y() - src_rect.y()) * height_scale,
+ r.width() * width_scale, r.height() * height_scale);
+}
+
+std::string RectF::ToString() const {
+ return base::StringPrintf("%s %s", origin().ToString().c_str(),
+ size().ToString().c_str());
+}
+
+bool RectF::ApproximatelyEqual(const RectF& rect,
+ float tolerance_x,
+ float tolerance_y) const {
+ return std::abs(x() - rect.x()) <= tolerance_x &&
+ std::abs(y() - rect.y()) <= tolerance_y &&
+ std::abs(right() - rect.right()) <= tolerance_x &&
+ std::abs(bottom() - rect.bottom()) <= tolerance_y;
+}
+
} // namespace gfx
diff --git a/ui/gfx/geometry/rect_f.h b/ui/gfx/geometry/rect_f.h
index acda35b..b135dd6 100644
--- a/ui/gfx/geometry/rect_f.h
+++ b/ui/gfx/geometry/rect_f.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,19 +9,19 @@
#include <string>
#include "build/build_config.h"
+#include "ui/gfx/geometry/insets_f.h"
+#include "ui/gfx/geometry/outsets_f.h"
#include "ui/gfx/geometry/point_f.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size_f.h"
#include "ui/gfx/geometry/vector2d_f.h"
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
typedef struct CGRect CGRect;
#endif
namespace gfx {
-class InsetsF;
-
// A floating version of gfx::Rect.
class GEOMETRY_EXPORT RectF {
public:
@@ -39,7 +39,7 @@
static_cast<float>(r.width()),
static_cast<float>(r.height())) {}
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
explicit RectF(const CGRect& r);
// Construct an equivalent CoreGraphics object.
CGRect ToCGRect() const;
@@ -88,27 +88,15 @@
size_.SetSize(width, height);
}
- // Shrink the rectangle by |inset| on all sides.
- void Inset(float inset) { Inset(inset, inset); }
- // Shrink the rectangle by a horizontal and vertical distance on all sides.
- void Inset(float horizontal, float vertical) {
- Inset(horizontal, vertical, horizontal, vertical);
- }
-
- // Shrink the rectangle by the given insets.
+ // Shrinks the rectangle by |inset| on all sides.
+ void Inset(float inset) { Inset(InsetsF(inset)); }
+ // Shrinks the rectangle by the given |insets|.
void Inset(const InsetsF& insets);
- // Shrink the rectangle by the specified amount on each side.
- void Inset(float left, float top, float right, float bottom);
-
- // Expand the rectangle by the specified amount on each side.
+ // Expands the rectangle by |outset| on all sides.
void Outset(float outset) { Inset(-outset); }
- void Outset(float horizontal, float vertical) {
- Inset(-horizontal, -vertical);
- }
- void Outset(float left, float top, float right, float bottom) {
- Inset(-left, -top, -right, -bottom);
- }
+ // Expands the rectangle by the given |outsets|.
+ void Outset(const OutsetsF& outsets) { Inset(outsets.ToInsets()); }
// Move the rectangle by a horizontal and vertical distance.
void Offset(float horizontal, float vertical);
@@ -119,7 +107,7 @@
InsetsF InsetsFrom(const RectF& inner) const;
// Returns true if the area of the rectangle is zero.
- bool IsEmpty() const { return size_.IsEmpty(); }
+ constexpr bool IsEmpty() const { return size_.IsEmpty(); }
// A rect is less than another rect if its origin is less than
// the other rect's origin. If the origins are equal, then the
@@ -130,8 +118,9 @@
bool operator<(const RectF& other) const;
// Returns true if the point identified by point_x and point_y falls inside
- // this rectangle. The point (x, y) is inside the rectangle, but the
- // point (x + width, y + height) is not.
+ // this rectangle (including the left and the top edges, excluding the right
+ // and the bottom edges). If this rectangle is empty, this method returns
+ // false regardless of the point.
bool Contains(float point_x, float point_y) const;
// Returns true if the specified point is contained by this rectangle.
@@ -139,6 +128,15 @@
return Contains(point.x(), point.y());
}
+ // Similar to Contains(), but uses edge-inclusive geometry, i.e. also returns
+ // true if the point is on the right or the bottom edge. If this rectangle
+ // is empty, this method returns true only if the point is at the origin of
+ // this rectangle.
+ bool InclusiveContains(float point_x, float point_y) const;
+ bool InclusiveContains(const PointF& point) const {
+ return InclusiveContains(point.x(), point.y());
+ }
+
// Returns true if this rectangle contains the specified rectangle.
bool Contains(const RectF& rect) const;
@@ -146,15 +144,31 @@
// An empty rectangle doesn't intersect any rectangle.
bool Intersects(const RectF& rect) const;
- // Computes the intersection of this rectangle with the given rectangle.
+ // Sets this rect to be the intersection of this rectangle with the given
+ // rectangle.
void Intersect(const RectF& rect);
- // Computes the union of this rectangle with the given rectangle. The union
- // is the smallest rectangle containing both rectangles.
+ // Sets this rect to be the intersection of itself and |rect| using
+ // edge-inclusive geometry. If the two rectangles overlap but the overlap
+ // region is zero-area (either because one of the two rectangles is zero-area,
+ // or because the rectangles overlap at an edge or a corner), the result is
+ // the zero-area intersection. The return value indicates whether the two
+ // rectangle actually have an intersection, since checking the result for
+ // isEmpty() is not conclusive.
+ bool InclusiveIntersect(const RectF& rect);
+
+ // Sets this rect to be the union of this rectangle with the given rectangle.
+ // The union is the smallest rectangle containing both rectangles if not
+ // empty. If both rects are empty, this rect will become |rect|.
void Union(const RectF& rect);
- // Computes the rectangle resulting from subtracting |rect| from |*this|,
- // i.e. the bounding rect of |Region(*this) - Region(rect)|.
+ // Similar to Union(), but the result will contain both rectangles even if
+ // either of them is empty. For example, union of (100, 100, 0x0) and
+ // (200, 200, 50x0) is (100, 100, 150x100).
+ void UnionEvenIfEmpty(const RectF& rect);
+
+ // Sets this rect to be the rectangle resulting from subtracting |rect| from
+ // |*this|, i.e. the bounding rect of |Region(*this) - Region(rect)|.
void Subtract(const RectF& rect);
// Fits as much of the receiving rectangle into the supplied rectangle as
@@ -191,6 +205,9 @@
// returns the smallest non-zero value appropriate for float.
float ManhattanInternalDistance(const RectF& rect) const;
+ // Returns the closest point in or on an edge of this rect to the given point.
+ PointF ClosestPoint(const PointF& point) const;
+
// Scales the rectangle by |scale|.
void Scale(float scale) {
Scale(scale, scale);
@@ -201,6 +218,14 @@
set_size(ScaleSize(size(), x_scale, y_scale));
}
+ // Divides the rectangle by |inv_scale|.
+ void InvScale(float inv_scale) { InvScale(inv_scale, inv_scale); }
+
+ void InvScale(float x_scale, float y_scale) {
+ origin_.InvScale(x_scale, y_scale);
+ size_.InvScale(x_scale, y_scale);
+ }
+
// This method reports if the RectF can be safely converted to an integer
// Rect. When it is false, some dimension of the RectF is outside the bounds
// of what an integer can represent, and converting it to a Rect will require
@@ -209,16 +234,20 @@
std::string ToString() const;
+ bool ApproximatelyEqual(const RectF& rect,
+ float tolerance_x,
+ float tolerance_y) const;
+
private:
PointF origin_;
SizeF size_;
};
-inline bool operator==(const RectF& lhs, const RectF& rhs) {
+constexpr bool operator==(const RectF& lhs, const RectF& rhs) {
return lhs.origin() == rhs.origin() && lhs.size() == rhs.size();
}
-inline bool operator!=(const RectF& lhs, const RectF& rhs) {
+constexpr bool operator!=(const RectF& lhs, const RectF& rhs) {
return !(lhs == rhs);
}
@@ -238,6 +267,7 @@
GEOMETRY_EXPORT RectF IntersectRects(const RectF& a, const RectF& b);
GEOMETRY_EXPORT RectF UnionRects(const RectF& a, const RectF& b);
+GEOMETRY_EXPORT RectF UnionRectsEvenIfEmpty(const RectF& a, const RectF& b);
GEOMETRY_EXPORT RectF SubtractRects(const RectF& a, const RectF& b);
inline RectF ScaleRect(const RectF& r, float x_scale, float y_scale) {
@@ -249,6 +279,10 @@
return ScaleRect(r, scale, scale);
}
+inline RectF TransposeRect(const RectF& r) {
+ return RectF(r.y(), r.x(), r.height(), r.width());
+}
+
// Constructs a rectangle with |p1| and |p2| as opposite corners.
//
// This could also be thought of as "the smallest rect that contains both
@@ -257,6 +291,15 @@
// contained within the rect, because they will appear on one of these edges.
GEOMETRY_EXPORT RectF BoundingRect(const PointF& p1, const PointF& p2);
+// Return a maximum rectangle in which any point is covered by either a or b.
+GEOMETRY_EXPORT RectF MaximumCoveredRect(const RectF& a, const RectF& b);
+
+// Returns the rect in |dest_rect| corresponding to |r] in |src_rect| when
+// |src_rect| is mapped to |dest_rect|.
+GEOMETRY_EXPORT RectF MapRect(const RectF& r,
+ const RectF& src_rect,
+ const RectF& dest_rect);
+
// This is declared here for use in gtest-based unit tests but is defined in
// the //ui/gfx:test_support target. Depend on that to use this in your unit
// test. This should not be used in production code - call ToString() instead.
diff --git a/ui/gfx/geometry/rect_f_unittest.cc b/ui/gfx/geometry/rect_f_unittest.cc
index d318255..3632d37 100644
--- a/ui/gfx/geometry/rect_f_unittest.cc
+++ b/ui/gfx/geometry/rect_f_unittest.cc
@@ -1,15 +1,358 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/rect_f.h"
+#include <cmath>
+
#include "ui/gfx/geometry/insets_f.h"
#include "ui/gfx/geometry/rect_f.h"
-#include "ui/gfx/test/gfx_util.h"
+#include "ui/gfx/geometry/test/geometry_util.h"
namespace gfx {
+TEST(RectFTest, FromRect) {
+ // Check that explicit conversion from integer to float compiles.
+ Rect a(10, 20, 30, 40);
+ RectF b(10, 20, 30, 40);
+
+ RectF c = RectF(a);
+ EXPECT_EQ(b, c);
+}
+
+TEST(RectFTest, ContainsPointF) {
+ EXPECT_FALSE(RectF().Contains(PointF()));
+ RectF r(10, 20, 30, 40);
+ EXPECT_FALSE(r.Contains(PointF(0, 0)));
+ EXPECT_FALSE(r.Contains(PointF(9.9999f, 20)));
+ EXPECT_FALSE(r.Contains(PointF(10, 19.9999f)));
+ EXPECT_TRUE(r.Contains(PointF(10, 20)));
+ EXPECT_TRUE(r.Contains(PointF(39.9999f, 20)));
+ EXPECT_FALSE(r.Contains(PointF(40, 20)));
+ EXPECT_TRUE(r.Contains(PointF(10, 59.9999f)));
+ EXPECT_FALSE(r.Contains(PointF(10, 60)));
+ EXPECT_TRUE(r.Contains(PointF(39.9999f, 59.9999f)));
+ EXPECT_FALSE(r.Contains(PointF(40, 60)));
+ EXPECT_FALSE(r.Contains(PointF(100, 100)));
+}
+
+TEST(RectFTest, ContainsXY) {
+ EXPECT_FALSE(RectF().Contains(0, 0));
+ RectF r(10, 20, 30, 40);
+ EXPECT_FALSE(r.Contains(0, 0));
+ EXPECT_FALSE(r.Contains(9.9999f, 20));
+ EXPECT_FALSE(r.Contains(10, 19.9999f));
+ EXPECT_TRUE(r.Contains(10, 20));
+ EXPECT_TRUE(r.Contains(39.9999f, 20));
+ EXPECT_FALSE(r.Contains(40, 20));
+ EXPECT_TRUE(r.Contains(10, 59.9999f));
+ EXPECT_FALSE(r.Contains(10, 60));
+ EXPECT_TRUE(r.Contains(39.9999f, 59.9999f));
+ EXPECT_FALSE(r.Contains(40, 60));
+ EXPECT_FALSE(r.Contains(100, 100));
+}
+
+TEST(RectFTest, InclusiveContainsPointF) {
+ EXPECT_TRUE(RectF().InclusiveContains(PointF()));
+ EXPECT_FALSE(RectF().InclusiveContains(PointF(0.0001f, 0)));
+ RectF r(10, 20, 30, 40);
+ EXPECT_FALSE(r.InclusiveContains(PointF(0, 0)));
+ EXPECT_FALSE(r.InclusiveContains(PointF(9.9999f, 20)));
+ EXPECT_FALSE(r.InclusiveContains(PointF(10, 19.9999f)));
+ EXPECT_TRUE(r.InclusiveContains(PointF(10, 20)));
+ EXPECT_TRUE(r.InclusiveContains(PointF(40, 20)));
+ EXPECT_FALSE(r.InclusiveContains(PointF(40.0001f, 20)));
+ EXPECT_TRUE(r.InclusiveContains(PointF(10, 60)));
+ EXPECT_FALSE(r.InclusiveContains(PointF(10, 60.0001f)));
+ EXPECT_TRUE(r.InclusiveContains(PointF(40, 60)));
+ EXPECT_FALSE(r.InclusiveContains(PointF(100, 100)));
+}
+
+TEST(RectFTest, InclusiveContainsXY) {
+ EXPECT_TRUE(RectF().InclusiveContains(0, 0));
+ EXPECT_FALSE(RectF().InclusiveContains(0.0001f, 0));
+ RectF r(10, 20, 30, 40);
+ EXPECT_FALSE(r.InclusiveContains(0, 0));
+ EXPECT_FALSE(r.InclusiveContains(9.9999f, 20));
+ EXPECT_FALSE(r.InclusiveContains(10, 19.9999f));
+ EXPECT_TRUE(r.InclusiveContains(10, 20));
+ EXPECT_TRUE(r.InclusiveContains(40, 20));
+ EXPECT_FALSE(r.InclusiveContains(40.0001f, 20));
+ EXPECT_TRUE(r.InclusiveContains(10, 60));
+ EXPECT_FALSE(r.InclusiveContains(10, 60.0001f));
+ EXPECT_TRUE(r.InclusiveContains(40, 60));
+ EXPECT_FALSE(r.InclusiveContains(100, 100));
+}
+
+TEST(RectFTest, BoundingRect) {
+ // If point B dominates A, then A should be the origin.
+ EXPECT_RECTF_EQ(RectF(4.2f, 6.8f, 0, 0),
+ BoundingRect(PointF(4.2f, 6.8f), PointF(4.2f, 6.8f)));
+ EXPECT_RECTF_EQ(RectF(4.2f, 6.8f, 4.3f, 0),
+ BoundingRect(PointF(4.2f, 6.8f), PointF(8.5f, 6.8f)));
+ EXPECT_RECTF_EQ(RectF(4.2f, 6.8f, 0, 2.5f),
+ BoundingRect(PointF(4.2f, 6.8f), PointF(4.2f, 9.3f)));
+ EXPECT_RECTF_EQ(RectF(4.2f, 6.8f, 4.3f, 2.5f),
+ BoundingRect(PointF(4.2f, 6.8f), PointF(8.5f, 9.3f)));
+ // If point A dominates B, then B should be the origin.
+ EXPECT_RECTF_EQ(RectF(4.2f, 6.8f, 0, 0),
+ BoundingRect(PointF(4.2f, 6.8f), PointF(4.2f, 6.8f)));
+ EXPECT_RECTF_EQ(RectF(4.2f, 6.8f, 4.3f, 0),
+ BoundingRect(PointF(8.5f, 6.8f), PointF(4.2f, 6.8f)));
+ EXPECT_RECTF_EQ(RectF(4.2f, 6.8f, 0, 2.5f),
+ BoundingRect(PointF(4.2f, 9.3f), PointF(4.2f, 6.8f)));
+ EXPECT_RECTF_EQ(RectF(4.2f, 6.8f, 4.3f, 2.5f),
+ BoundingRect(PointF(8.5f, 9.3f), PointF(4.2f, 6.8f)));
+ // If neither point dominates, then the origin is a combination of the two.
+ EXPECT_RECTF_EQ(RectF(4.2f, 4.2f, 2.6f, 2.6f),
+ BoundingRect(PointF(4.2f, 6.8f), PointF(6.8f, 4.2f)));
+ EXPECT_RECTF_EQ(RectF(-6.8f, -6.8f, 2.6f, 2.6f),
+ BoundingRect(PointF(-4.2f, -6.8f), PointF(-6.8f, -4.2f)));
+ EXPECT_RECTF_EQ(RectF(-4.2f, -4.2f, 11.0f, 11.0f),
+ BoundingRect(PointF(-4.2f, 6.8f), PointF(6.8f, -4.2f)));
+}
+
+TEST(RectFTest, Union) {
+ EXPECT_RECTF_EQ(RectF(), UnionRects(RectF(), RectF()));
+ EXPECT_RECTF_EQ(
+ RectF(1.1f, 2.2f, 3.3f, 4.4f),
+ UnionRects(RectF(1.1f, 2.2f, 3.3f, 4.4f), RectF(1.1f, 2.2f, 3.3f, 4.4f)));
+ EXPECT_RECTF_EQ(
+ RectF(0, 0, 8.8f, 11.0f),
+ UnionRects(RectF(0, 0, 3.3f, 4.4f), RectF(3.3f, 4.4f, 5.5f, 6.6f)));
+ EXPECT_RECTF_EQ(
+ RectF(0, 0, 8.8f, 11.0f),
+ UnionRects(RectF(3.3f, 4.4f, 5.5f, 6.6f), RectF(0, 0, 3.3f, 4.4f)));
+ EXPECT_RECTF_EQ(
+ RectF(0, 1.1f, 3.3f, 8.8f),
+ UnionRects(RectF(0, 1.1f, 3.3f, 4.4f), RectF(0, 5.5f, 3.3f, 4.4f)));
+ EXPECT_RECTF_EQ(
+ RectF(0, 1.1f, 11.0f, 12.1f),
+ UnionRects(RectF(0, 1.1f, 3.3f, 4.4f), RectF(4.4f, 5.5f, 6.6f, 7.7f)));
+ EXPECT_RECTF_EQ(
+ RectF(0, 1.1f, 11.0f, 12.1f),
+ UnionRects(RectF(4.4f, 5.5f, 6.6f, 7.7f), RectF(0, 1.1f, 3.3f, 4.4f)));
+ EXPECT_RECTF_EQ(
+ RectF(2.2f, 3.3f, 4.4f, 5.5f),
+ UnionRects(RectF(8.8f, 9.9f, 0, 2.2f), RectF(2.2f, 3.3f, 4.4f, 5.5f)));
+ EXPECT_RECTF_EQ(
+ RectF(2.2f, 3.3f, 4.4f, 5.5f),
+ UnionRects(RectF(2.2f, 3.3f, 4.4f, 5.5f), RectF(8.8f, 9.9f, 2.2f, 0)));
+}
+
+TEST(RectFTest, UnionEvenIfEmpty) {
+ EXPECT_RECTF_EQ(RectF(), UnionRectsEvenIfEmpty(RectF(), RectF()));
+ EXPECT_RECTF_EQ(RectF(0, 0, 3.3f, 4.4f),
+ UnionRectsEvenIfEmpty(RectF(), RectF(3.3f, 4.4f, 0, 0)));
+ EXPECT_RECTF_EQ(RectF(0, 0, 8.8f, 11.0f),
+ UnionRectsEvenIfEmpty(RectF(0, 0, 3.3f, 4.4f),
+ RectF(3.3f, 4.4f, 5.5f, 6.6f)));
+ EXPECT_RECTF_EQ(RectF(0, 0, 8.8f, 11.0f),
+ UnionRectsEvenIfEmpty(RectF(3.3f, 4.4f, 5.5f, 6.6f),
+ RectF(0, 0, 3.3f, 4.4f)));
+ EXPECT_RECTF_EQ(RectF(2.2f, 3.3f, 6.6f, 8.8f),
+ UnionRectsEvenIfEmpty(RectF(8.8f, 9.9f, 0, 2.2f),
+ RectF(2.2f, 3.3f, 4.4f, 5.5f)));
+ EXPECT_RECTF_EQ(RectF(2.2f, 3.3f, 8.8f, 6.6f),
+ UnionRectsEvenIfEmpty(RectF(2.2f, 3.3f, 4.4f, 5.5f),
+ RectF(8.8f, 9.9f, 2.2f, 0)));
+}
+
+TEST(RectFTest, UnionEnsuresContainWithFloatingError) {
+ for (float f = 0.1f; f < 5; f += 0.1f) {
+ RectF r1(1, 2, 3, 4);
+ r1.Scale(f, f + 0.05f);
+ RectF r2 = r1 + Vector2dF(10.f + f, f - 10.f);
+ RectF r3 = UnionRects(r1, r2);
+ EXPECT_TRUE(r3.Contains(r1));
+ EXPECT_TRUE(r3.Contains(r2));
+ }
+}
+
+TEST(RectFTest, UnionIfEmptyResultTinySize) {
+ RectF r1(1e-15f, 0, 0, 0);
+ RectF r2(0, 1e-15f, 0, 0);
+ RectF r3 = UnionRectsEvenIfEmpty(r1, r2);
+ EXPECT_FALSE(r3.IsEmpty());
+ EXPECT_TRUE(r3.Contains(r1));
+ EXPECT_TRUE(r3.Contains(r2));
+}
+
+TEST(RectFTest, UnionMaxRects) {
+ constexpr float kMaxFloat = std::numeric_limits<float>::max();
+ constexpr float kMinFloat = std::numeric_limits<float>::min();
+ gfx::RectF r1(kMinFloat, 0, kMaxFloat, kMaxFloat);
+ gfx::RectF r2(0, kMinFloat, kMaxFloat, kMaxFloat);
+ // This should not trigger DCHECK failure.
+ r1.Union(r2);
+}
+
+TEST(RectFTest, CenterPoint) {
+ PointF center;
+
+ // When origin is (0, 0).
+ center = RectF(0, 0, 20, 20).CenterPoint();
+ EXPECT_TRUE(center == PointF(10, 10));
+
+ // When origin is even.
+ center = RectF(10, 10, 20, 20).CenterPoint();
+ EXPECT_TRUE(center == PointF(20, 20));
+
+ // When origin is odd.
+ center = RectF(11, 11, 20, 20).CenterPoint();
+ EXPECT_TRUE(center == PointF(21, 21));
+
+ // When 0 width or height.
+ center = RectF(10, 10, 0, 20).CenterPoint();
+ EXPECT_TRUE(center == PointF(10, 20));
+ center = RectF(10, 10, 20, 0).CenterPoint();
+ EXPECT_TRUE(center == PointF(20, 10));
+
+ // When an odd size.
+ center = RectF(10, 10, 21, 21).CenterPoint();
+ EXPECT_TRUE(center == PointF(20.5f, 20.5f));
+
+ // When an odd size and position.
+ center = RectF(11, 11, 21, 21).CenterPoint();
+ EXPECT_TRUE(center == PointF(21.5f, 21.5f));
+}
+
+TEST(RectFTest, ScaleRect) {
+ constexpr RectF input(3, 3, 3, 3);
+ EXPECT_RECTF_EQ(RectF(4.5f, 4.5f, 4.5f, 4.5f), ScaleRect(input, 1.5f));
+ EXPECT_RECTF_EQ(RectF(0, 0, 0, 0), ScaleRect(input, 0));
+
+ constexpr float kMaxFloat = std::numeric_limits<float>::max();
+ EXPECT_RECTF_EQ(RectF(kMaxFloat, kMaxFloat, kMaxFloat, kMaxFloat),
+ ScaleRect(input, kMaxFloat));
+
+ RectF nan_rect = ScaleRect(input, std::numeric_limits<float>::quiet_NaN());
+ EXPECT_TRUE(std::isnan(nan_rect.x()));
+ EXPECT_TRUE(std::isnan(nan_rect.y()));
+ // NaN is clamped to 0 in SizeF constructor.
+ EXPECT_EQ(0, nan_rect.width());
+ EXPECT_EQ(0, nan_rect.height());
+}
+
+TEST(RectFTest, IsExpressibleAsRect) {
+ EXPECT_TRUE(RectF().IsExpressibleAsRect());
+
+ constexpr float kMinIntF =
+ static_cast<float>(std::numeric_limits<int>::min());
+ constexpr float kMaxIntF =
+ static_cast<float>(std::numeric_limits<int>::max());
+ constexpr float kInfinity = std::numeric_limits<float>::infinity();
+
+ EXPECT_TRUE(
+ RectF(kMinIntF + 200, kMinIntF + 200, kMaxIntF - 200, kMaxIntF - 200)
+ .IsExpressibleAsRect());
+ EXPECT_FALSE(
+ RectF(kMinIntF - 200, kMinIntF + 200, kMaxIntF + 200, kMaxIntF + 200)
+ .IsExpressibleAsRect());
+ EXPECT_FALSE(
+ RectF(kMinIntF + 200, kMinIntF - 200, kMaxIntF + 200, kMaxIntF + 200)
+ .IsExpressibleAsRect());
+ EXPECT_FALSE(
+ RectF(kMinIntF + 200, kMinIntF + 200, kMaxIntF + 200, kMaxIntF - 200)
+ .IsExpressibleAsRect());
+ EXPECT_FALSE(
+ RectF(kMinIntF + 200, kMinIntF + 200, kMaxIntF - 200, kMaxIntF + 200)
+ .IsExpressibleAsRect());
+
+ EXPECT_TRUE(
+ RectF(0, 0, kMaxIntF - 200, kMaxIntF - 200).IsExpressibleAsRect());
+ EXPECT_FALSE(
+ RectF(200, 0, kMaxIntF + 200, kMaxIntF - 200).IsExpressibleAsRect());
+ EXPECT_FALSE(
+ RectF(0, 200, kMaxIntF - 200, kMaxIntF + 200).IsExpressibleAsRect());
+ EXPECT_FALSE(
+ RectF(0, 0, kMaxIntF + 200, kMaxIntF - 200).IsExpressibleAsRect());
+ EXPECT_FALSE(
+ RectF(0, 0, kMaxIntF - 200, kMaxIntF + 200).IsExpressibleAsRect());
+
+ EXPECT_FALSE(RectF(kInfinity, 0, 1, 1).IsExpressibleAsRect());
+ EXPECT_FALSE(RectF(0, kInfinity, 1, 1).IsExpressibleAsRect());
+ EXPECT_FALSE(RectF(0, 0, kInfinity, 1).IsExpressibleAsRect());
+ EXPECT_FALSE(RectF(0, 0, 1, kInfinity).IsExpressibleAsRect());
+}
+
+TEST(RectFTest, Offset) {
+ RectF f(1.1f, 2.2f, 3.3f, 4.4f);
+ EXPECT_EQ(RectF(2.2f, 1.1f, 3.3f, 4.4f), (f + Vector2dF(1.1f, -1.1f)));
+ EXPECT_EQ(RectF(2.2f, 1.1f, 3.3f, 4.4f), (Vector2dF(1.1f, -1.1f) + f));
+ f += Vector2dF(1.1f, -1.1f);
+ EXPECT_EQ(RectF(2.2f, 1.1f, 3.3f, 4.4f), f);
+ EXPECT_EQ(RectF(1.1f, 2.2f, 3.3f, 4.4f), (f - Vector2dF(1.1f, -1.1f)));
+ f -= Vector2dF(1.1f, -1.1f);
+ EXPECT_EQ(RectF(1.1f, 2.2f, 3.3f, 4.4f), f);
+}
+
+TEST(RectFTest, Corners) {
+ RectF f(1.1f, 2.1f, 3.1f, 4.1f);
+ EXPECT_EQ(PointF(1.1f, 2.1f), f.origin());
+ EXPECT_EQ(PointF(4.2f, 2.1f), f.top_right());
+ EXPECT_EQ(PointF(1.1f, 6.2f), f.bottom_left());
+ EXPECT_EQ(PointF(4.2f, 6.2f), f.bottom_right());
+}
+
+TEST(RectFTest, Centers) {
+ RectF f(10.1f, 20.2f, 30.3f, 40.4f);
+ EXPECT_EQ(PointF(10.1f, 40.4f), f.left_center());
+ EXPECT_EQ(PointF(25.25f, 20.2f), f.top_center());
+ EXPECT_EQ(PointF(40.4f, 40.4f), f.right_center());
+ EXPECT_EQ(25.25f, f.bottom_center().x());
+ EXPECT_NEAR(60.6f, f.bottom_center().y(), 0.001f);
+}
+
+TEST(RectFTest, Transpose) {
+ RectF f(10.1f, 20.2f, 30.3f, 40.4f);
+ f.Transpose();
+ EXPECT_EQ(RectF(20.2f, 10.1f, 40.4f, 30.3f), f);
+}
+
+TEST(RectFTest, ManhattanDistanceToPoint) {
+ RectF f(1.1f, 2.1f, 3.1f, 4.1f);
+ EXPECT_FLOAT_EQ(0.f, f.ManhattanDistanceToPoint(PointF(1.1f, 2.1f)));
+ EXPECT_FLOAT_EQ(0.f, f.ManhattanDistanceToPoint(PointF(4.2f, 6.f)));
+ EXPECT_FLOAT_EQ(0.f, f.ManhattanDistanceToPoint(PointF(2.f, 4.f)));
+ EXPECT_FLOAT_EQ(3.2f, f.ManhattanDistanceToPoint(PointF(0.f, 0.f)));
+ EXPECT_FLOAT_EQ(2.1f, f.ManhattanDistanceToPoint(PointF(2.f, 0.f)));
+ EXPECT_FLOAT_EQ(2.9f, f.ManhattanDistanceToPoint(PointF(5.f, 0.f)));
+ EXPECT_FLOAT_EQ(.8f, f.ManhattanDistanceToPoint(PointF(5.f, 4.f)));
+ EXPECT_FLOAT_EQ(2.6f, f.ManhattanDistanceToPoint(PointF(5.f, 8.f)));
+ EXPECT_FLOAT_EQ(1.8f, f.ManhattanDistanceToPoint(PointF(3.f, 8.f)));
+ EXPECT_FLOAT_EQ(1.9f, f.ManhattanDistanceToPoint(PointF(0.f, 7.f)));
+ EXPECT_FLOAT_EQ(1.1f, f.ManhattanDistanceToPoint(PointF(0.f, 3.f)));
+}
+
+TEST(RectFTest, ManhattanInternalDistance) {
+ RectF f(0.0f, 0.0f, 400.0f, 400.0f);
+ static const float kEpsilon = std::numeric_limits<float>::epsilon();
+
+ EXPECT_FLOAT_EQ(0.0f,
+ f.ManhattanInternalDistance(RectF(-1.0f, 0.0f, 2.0f, 1.0f)));
+ EXPECT_FLOAT_EQ(
+ kEpsilon, f.ManhattanInternalDistance(RectF(400.0f, 0.0f, 1.0f, 400.0f)));
+ EXPECT_FLOAT_EQ(2.0f * kEpsilon, f.ManhattanInternalDistance(RectF(
+ -100.0f, -100.0f, 100.0f, 100.0f)));
+ EXPECT_FLOAT_EQ(1.0f + kEpsilon, f.ManhattanInternalDistance(
+ RectF(-101.0f, 100.0f, 100.0f, 100.0f)));
+ EXPECT_FLOAT_EQ(
+ 2.0f + 2.0f * kEpsilon,
+ f.ManhattanInternalDistance(RectF(-101.0f, -101.0f, 100.0f, 100.0f)));
+ EXPECT_FLOAT_EQ(
+ 433.0f + 2.0f * kEpsilon,
+ f.ManhattanInternalDistance(RectF(630.0f, 603.0f, 100.0f, 100.0f)));
+
+ EXPECT_FLOAT_EQ(0.0f,
+ f.ManhattanInternalDistance(RectF(-1.0f, 0.0f, 1.1f, 1.0f)));
+ EXPECT_FLOAT_EQ(0.1f + kEpsilon,
+ f.ManhattanInternalDistance(RectF(-1.5f, 0.0f, 1.4f, 1.0f)));
+ EXPECT_FLOAT_EQ(kEpsilon,
+ f.ManhattanInternalDistance(RectF(-1.5f, 0.0f, 1.5f, 1.0f)));
+}
+
TEST(RectFTest, Inset) {
RectF r(10, 20, 30, 40);
r.Inset(0);
@@ -19,21 +362,21 @@
r.Inset(-1.5);
EXPECT_RECTF_EQ(RectF(10, 20, 30, 40), r);
- r.Inset(1.5, 2.25);
+ r.Inset(InsetsF::VH(2.25, 1.5));
EXPECT_RECTF_EQ(RectF(11.5, 22.25, 27, 35.5), r);
- r.Inset(-1.5, -2.25);
+ r.Inset(InsetsF::VH(-2.25, -1.5));
EXPECT_RECTF_EQ(RectF(10, 20, 30, 40), r);
// The parameters are left, top, right, bottom.
- r.Inset(1.5, 2.25, 3.75, 4);
+ r.Inset(InsetsF::TLBR(2.25, 1.5, 4, 3.75));
EXPECT_RECTF_EQ(RectF(11.5, 22.25, 24.75, 33.75), r);
- r.Inset(-1.5, -2.25, -3.75, -4);
+ r.Inset(InsetsF::TLBR(-2.25, -1.5, -4, -3.75));
EXPECT_RECTF_EQ(RectF(10, 20, 30, 40), r);
// InsetsF parameters are top, right, bottom, left.
- r.Inset(InsetsF(1.5, 2.25, 3.75, 4));
+ r.Inset(InsetsF::TLBR(1.5, 2.25, 3.75, 4));
EXPECT_RECTF_EQ(RectF(12.25, 21.5, 23.75, 34.75), r);
- r.Inset(InsetsF(-1.5, -2.25, -3.75, -4));
+ r.Inset(InsetsF::TLBR(-1.5, -2.25, -3.75, -4));
EXPECT_RECTF_EQ(RectF(10, 20, 30, 40), r);
}
@@ -46,14 +389,14 @@
r.Outset(-1.5);
EXPECT_RECTF_EQ(RectF(10, 20, 30, 40), r);
- r.Outset(1.5, 2.25);
+ r.Outset(OutsetsF::VH(2.25, 1.5));
EXPECT_RECTF_EQ(RectF(8.5, 17.75, 33, 44.5), r);
- r.Outset(-1.5, -2.25);
+ r.Outset(OutsetsF::VH(-2.25, -1.5));
EXPECT_RECTF_EQ(RectF(10, 20, 30, 40), r);
- r.Outset(1.5, 2.25, 3.75, 4);
+ r.Outset(OutsetsF::TLBR(2.25, 1.5, 4, 3.75));
EXPECT_RECTF_EQ(RectF(8.5, 17.75, 35.25, 46.25), r);
- r.Outset(-1.5, -2.25, -3.75, -4);
+ r.Outset(OutsetsF::TLBR(-2.25, -1.5, -4, -3.75));
EXPECT_RECTF_EQ(RectF(10, 20, 30, 40), r);
}
@@ -64,15 +407,122 @@
r.Inset(-18);
EXPECT_RECTF_EQ(RectF(10, 20, 36, 40), r);
- r.Inset(15, 30);
+ r.Inset(InsetsF::VH(30, 15));
EXPECT_RECTF_EQ(RectF(25, 50, 6, 0), r);
- r.Inset(-15, -30);
+ r.Inset(InsetsF::VH(-30, -15));
EXPECT_RECTF_EQ(RectF(10, 20, 36, 60), r);
- r.Inset(20, 30, 40, 50);
+ r.Inset(InsetsF::TLBR(30, 20, 50, 40));
EXPECT_RECTF_EQ(RectF(30, 50, 0, 0), r);
- r.Inset(-20, -30, -40, -50);
+ r.Inset(InsetsF::TLBR(-30, -20, -50, -40));
EXPECT_RECTF_EQ(RectF(10, 20, 60, 80), r);
}
+TEST(RectFTest, InclusiveIntersect) {
+ RectF rect(11, 12, 0, 0);
+ EXPECT_TRUE(rect.InclusiveIntersect(RectF(11, 12, 13, 14)));
+ EXPECT_RECTF_EQ(RectF(11, 12, 0, 0), rect);
+
+ rect = RectF(11, 12, 13, 14);
+ EXPECT_TRUE(rect.InclusiveIntersect(RectF(24, 8, 0, 7)));
+ EXPECT_RECTF_EQ(RectF(24, 12, 0, 3), rect);
+
+ rect = RectF(11, 12, 13, 14);
+ EXPECT_TRUE(rect.InclusiveIntersect(RectF(9, 15, 4, 0)));
+ EXPECT_RECTF_EQ(RectF(11, 15, 2, 0), rect);
+
+ rect = RectF(11, 12, 0, 14);
+ EXPECT_FALSE(rect.InclusiveIntersect(RectF(12, 13, 15, 16)));
+ EXPECT_RECTF_EQ(RectF(), rect);
+}
+
+TEST(RectFTest, MaximumCoveredRect) {
+ // X aligned and intersect: unite.
+ EXPECT_EQ(RectF(10, 20, 30, 60),
+ MaximumCoveredRect(RectF(10, 20, 30, 40), RectF(10, 30, 30, 50)));
+ // X aligned and adjacent: unite.
+ EXPECT_EQ(RectF(10, 20, 30, 90),
+ MaximumCoveredRect(RectF(10, 20, 30, 40), RectF(10, 60, 30, 50)));
+ // X aligned and separate: choose the bigger one.
+ EXPECT_EQ(RectF(10, 61, 30, 50),
+ MaximumCoveredRect(RectF(10, 20, 30, 40), RectF(10, 61, 30, 50)));
+ // Y aligned and intersect: unite.
+ EXPECT_EQ(RectF(10, 20, 60, 40),
+ MaximumCoveredRect(RectF(10, 20, 30, 40), RectF(30, 20, 40, 40)));
+ // Y aligned and adjacent: unite.
+ EXPECT_EQ(RectF(10, 20, 70, 40),
+ MaximumCoveredRect(RectF(10, 20, 30, 40), RectF(40, 20, 40, 40)));
+ // Y aligned and separate: choose the bigger one.
+ EXPECT_EQ(RectF(41, 20, 40, 40),
+ MaximumCoveredRect(RectF(10, 20, 30, 40), RectF(41, 20, 40, 40)));
+ // Get the biggest expanded intersection.
+ EXPECT_EQ(RectF(0, 0, 9, 19),
+ MaximumCoveredRect(RectF(0, 0, 10, 10), RectF(0, 9, 9, 10)));
+ EXPECT_EQ(RectF(0, 0, 19, 9),
+ MaximumCoveredRect(RectF(0, 0, 10, 10), RectF(9, 0, 10, 9)));
+ // Otherwise choose the bigger one.
+ EXPECT_EQ(RectF(20, 30, 40, 50),
+ MaximumCoveredRect(RectF(10, 20, 30, 40), RectF(20, 30, 40, 50)));
+ EXPECT_EQ(RectF(10, 20, 40, 50),
+ MaximumCoveredRect(RectF(10, 20, 40, 50), RectF(20, 30, 30, 40)));
+ EXPECT_EQ(RectF(10, 20, 40, 50),
+ MaximumCoveredRect(RectF(10, 20, 40, 50), RectF(20, 30, 40, 50)));
+}
+
+TEST(RectFTest, ClosestPoint) {
+ // r.x()=50 r.right()=350
+ // | |
+ // 1 | 2 | 3
+ // ------+----------+--------r.y()=100
+ // 4 | 5(in) | 6
+ // ------+----------+--------r.bottom()=250
+ // 7 | 8 | 9
+
+ RectF r(50, 100, 300, 150);
+ // 1
+ EXPECT_EQ(PointF(50, 100), r.ClosestPoint(PointF(10, 20)));
+ // 2
+ EXPECT_EQ(PointF(110, 100), r.ClosestPoint(PointF(110, 80)));
+ // 3
+ EXPECT_EQ(PointF(350, 100), r.ClosestPoint(PointF(400, 80)));
+ // 4
+ EXPECT_EQ(PointF(50, 110), r.ClosestPoint(PointF(10, 110)));
+ // 5
+ EXPECT_EQ(PointF(50, 100), r.ClosestPoint(PointF(50, 100)));
+ EXPECT_EQ(PointF(150, 100), r.ClosestPoint(PointF(150, 100)));
+ EXPECT_EQ(PointF(350, 100), r.ClosestPoint(PointF(350, 100)));
+ EXPECT_EQ(PointF(350, 150), r.ClosestPoint(PointF(350, 150)));
+ EXPECT_EQ(PointF(350, 250), r.ClosestPoint(PointF(350, 250)));
+ EXPECT_EQ(PointF(150, 250), r.ClosestPoint(PointF(150, 250)));
+ EXPECT_EQ(PointF(50, 250), r.ClosestPoint(PointF(50, 250)));
+ EXPECT_EQ(PointF(50, 150), r.ClosestPoint(PointF(50, 150)));
+ EXPECT_EQ(PointF(150, 150), r.ClosestPoint(PointF(150, 150)));
+ // 6
+ EXPECT_EQ(PointF(350, 150), r.ClosestPoint(PointF(380, 150)));
+ // 7
+ EXPECT_EQ(PointF(50, 250), r.ClosestPoint(PointF(10, 280)));
+ // 8
+ EXPECT_EQ(PointF(180, 250), r.ClosestPoint(PointF(180, 300)));
+ // 9
+ EXPECT_EQ(PointF(350, 250), r.ClosestPoint(PointF(450, 450)));
+}
+
+TEST(RectFTest, MapRect) {
+ EXPECT_RECTF_EQ(RectF(), MapRect(RectF(), RectF(), RectF()));
+ EXPECT_RECTF_EQ(RectF(),
+ MapRect(RectF(1, 2, 3, 4), RectF(), RectF(5, 6, 7, 8)));
+ EXPECT_RECTF_EQ(
+ RectF(1, 2, 3, 4),
+ MapRect(RectF(1, 2, 3, 4), RectF(5, 6, 7, 8), RectF(5, 6, 7, 8)));
+ EXPECT_RECTF_EQ(
+ RectF(5, 6, 7, 8),
+ MapRect(RectF(1, 2, 3, 4), RectF(1, 2, 3, 4), RectF(5, 6, 7, 8)));
+ EXPECT_RECTF_EQ(
+ RectF(200, 300, 300, 400),
+ MapRect(RectF(1, 2, 3, 4), RectF(0, 1, 6, 8), RectF(100, 200, 600, 800)));
+ EXPECT_RECTF_EQ(RectF(1, 2, 3, 4),
+ MapRect(RectF(200, 300, 300, 400), RectF(100, 200, 600, 800),
+ RectF(0, 1, 6, 8)));
+}
+
} // namespace gfx
diff --git a/ui/gfx/geometry/rect_unittest.cc b/ui/gfx/geometry/rect_unittest.cc
index 6aceed3..832b5d1 100644
--- a/ui/gfx/geometry/rect_unittest.cc
+++ b/ui/gfx/geometry/rect_unittest.cc
@@ -1,25 +1,28 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <limits>
+#include "ui/gfx/geometry/rect.h"
#include <stddef.h>
-#include "base/cxx17_backports.h"
+#include <limits>
+
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/insets.h"
-#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/test/gfx_util.h"
+#include "ui/gfx/geometry/test/geometry_util.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#endif
namespace gfx {
+constexpr int kMaxInt = std::numeric_limits<int>::max();
+constexpr int kMinInt = std::numeric_limits<int>::min();
+
TEST(RectTest, Contains) {
static const struct ContainsCase {
int rect_x;
@@ -41,7 +44,7 @@
{0, 0, -10, -10, 0, 0, false},
#endif
};
- for (size_t i = 0; i < base::size(contains_cases); ++i) {
+ for (size_t i = 0; i < std::size(contains_cases); ++i) {
const ContainsCase& value = contains_cases[i];
Rect rect(value.rect_x, value.rect_y, value.rect_width, value.rect_height);
EXPECT_EQ(value.contained, rect.Contains(value.point_x, value.point_y));
@@ -71,7 +74,7 @@
{ 10, 10, 10, 10, 20, 15, 10, 10, false },
{ 10, 10, 10, 10, 21, 15, 10, 10, false }
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
EXPECT_EQ(tests[i].intersects, r1.Intersects(r2));
@@ -113,65 +116,55 @@
0, 0, 2, 2,
0, 0, 0, 0 }
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
Rect r3(tests[i].x3, tests[i].y3, tests[i].w3, tests[i].h3);
- Rect ir = IntersectRects(r1, r2);
- EXPECT_EQ(r3.x(), ir.x());
- EXPECT_EQ(r3.y(), ir.y());
- EXPECT_EQ(r3.width(), ir.width());
- EXPECT_EQ(r3.height(), ir.height());
+ EXPECT_EQ(r3, IntersectRects(r1, r2));
}
}
+TEST(RectTest, InclusiveIntersect) {
+ Rect rect(11, 12, 0, 0);
+ EXPECT_TRUE(rect.InclusiveIntersect(Rect(11, 12, 13, 14)));
+ EXPECT_EQ(Rect(11, 12, 0, 0), rect);
+
+ rect = Rect(11, 12, 13, 14);
+ EXPECT_TRUE(rect.InclusiveIntersect(Rect(24, 8, 0, 7)));
+ EXPECT_EQ(Rect(24, 12, 0, 3), rect);
+
+ rect = Rect(11, 12, 13, 14);
+ EXPECT_TRUE(rect.InclusiveIntersect(Rect(9, 15, 4, 0)));
+ EXPECT_EQ(Rect(11, 15, 2, 0), rect);
+
+ rect = Rect(11, 12, 0, 14);
+ EXPECT_FALSE(rect.InclusiveIntersect(Rect(12, 13, 15, 16)));
+ EXPECT_EQ(Rect(), rect);
+}
+
TEST(RectTest, Union) {
- static const struct Test {
- int x1; // rect 1
- int y1;
- int w1;
- int h1;
- int x2; // rect 2
- int y2;
- int w2;
- int h2;
- int x3; // rect 3: the union of rects 1 and 2
- int y3;
- int w3;
- int h3;
- } tests[] = {
- { 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0 },
- { 0, 0, 4, 4,
- 0, 0, 4, 4,
- 0, 0, 4, 4 },
- { 0, 0, 4, 4,
- 4, 4, 4, 4,
- 0, 0, 8, 8 },
- { 0, 0, 4, 4,
- 0, 5, 4, 4,
- 0, 0, 4, 9 },
- { 0, 0, 2, 2,
- 3, 3, 2, 2,
- 0, 0, 5, 5 },
- { 3, 3, 2, 2, // reverse r1 and r2 from previous test
- 0, 0, 2, 2,
- 0, 0, 5, 5 },
- { 0, 0, 0, 0, // union with empty rect
- 2, 2, 2, 2,
- 2, 2, 2, 2 }
- };
- for (size_t i = 0; i < base::size(tests); ++i) {
- Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
- Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
- Rect r3(tests[i].x3, tests[i].y3, tests[i].w3, tests[i].h3);
- Rect u = UnionRects(r1, r2);
- EXPECT_EQ(r3.x(), u.x());
- EXPECT_EQ(r3.y(), u.y());
- EXPECT_EQ(r3.width(), u.width());
- EXPECT_EQ(r3.height(), u.height());
- }
+ EXPECT_EQ(Rect(), UnionRects(Rect(), Rect()));
+ EXPECT_EQ(Rect(1, 2, 3, 4), UnionRects(Rect(1, 2, 3, 4), Rect(1, 2, 3, 4)));
+ EXPECT_EQ(Rect(0, 0, 8, 10), UnionRects(Rect(0, 0, 3, 4), Rect(3, 4, 5, 6)));
+ EXPECT_EQ(Rect(0, 0, 8, 10), UnionRects(Rect(3, 4, 5, 6), Rect(0, 0, 3, 4)));
+ EXPECT_EQ(Rect(0, 1, 3, 8), UnionRects(Rect(0, 1, 3, 4), Rect(0, 5, 3, 4)));
+ EXPECT_EQ(Rect(0, 1, 10, 11), UnionRects(Rect(0, 1, 3, 4), Rect(4, 5, 6, 7)));
+ EXPECT_EQ(Rect(0, 1, 10, 11), UnionRects(Rect(4, 5, 6, 7), Rect(0, 1, 3, 4)));
+ EXPECT_EQ(Rect(2, 3, 4, 5), UnionRects(Rect(8, 9, 0, 2), Rect(2, 3, 4, 5)));
+ EXPECT_EQ(Rect(2, 3, 4, 5), UnionRects(Rect(2, 3, 4, 5), Rect(8, 9, 2, 0)));
+}
+
+TEST(RectTest, UnionEvenIfEmpty) {
+ EXPECT_EQ(Rect(), UnionRectsEvenIfEmpty(Rect(), Rect()));
+ EXPECT_EQ(Rect(0, 0, 3, 4), UnionRectsEvenIfEmpty(Rect(), Rect(3, 4, 0, 0)));
+ EXPECT_EQ(Rect(0, 0, 8, 10),
+ UnionRectsEvenIfEmpty(Rect(0, 0, 3, 4), Rect(3, 4, 5, 6)));
+ EXPECT_EQ(Rect(0, 0, 8, 10),
+ UnionRectsEvenIfEmpty(Rect(3, 4, 5, 6), Rect(0, 0, 3, 4)));
+ EXPECT_EQ(Rect(2, 3, 6, 8),
+ UnionRectsEvenIfEmpty(Rect(8, 9, 0, 2), Rect(2, 3, 4, 5)));
+ EXPECT_EQ(Rect(2, 3, 8, 6),
+ UnionRectsEvenIfEmpty(Rect(2, 3, 4, 5), Rect(8, 9, 2, 0)));
}
TEST(RectTest, Equals) {
@@ -214,16 +207,13 @@
0, 0, 3, 3,
2, 2, 1, 1 }
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
Rect r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
Rect r3(tests[i].x3, tests[i].y3, tests[i].w3, tests[i].h3);
Rect u = r1;
u.AdjustToFit(r2);
- EXPECT_EQ(r3.x(), u.x());
- EXPECT_EQ(r3.y(), u.y());
- EXPECT_EQ(r3.width(), u.width());
- EXPECT_EQ(r3.height(), u.height());
+ EXPECT_EQ(r3, u);
}
}
@@ -358,36 +348,6 @@
EXPECT_TRUE(center == Point(21, 21));
}
-TEST(RectTest, CenterPointF) {
- PointF center;
-
- // When origin is (0, 0).
- center = RectF(0, 0, 20, 20).CenterPoint();
- EXPECT_TRUE(center == PointF(10, 10));
-
- // When origin is even.
- center = RectF(10, 10, 20, 20).CenterPoint();
- EXPECT_TRUE(center == PointF(20, 20));
-
- // When origin is odd.
- center = RectF(11, 11, 20, 20).CenterPoint();
- EXPECT_TRUE(center == PointF(21, 21));
-
- // When 0 width or height.
- center = RectF(10, 10, 0, 20).CenterPoint();
- EXPECT_TRUE(center == PointF(10, 20));
- center = RectF(10, 10, 20, 0).CenterPoint();
- EXPECT_TRUE(center == PointF(20, 10));
-
- // When an odd size.
- center = RectF(10, 10, 21, 21).CenterPoint();
- EXPECT_TRUE(center == PointF(20.5f, 20.5f));
-
- // When an odd size and position.
- center = RectF(11, 11, 21, 21).CenterPoint();
- EXPECT_TRUE(center == PointF(21.5f, 21.5f));
-}
-
TEST(RectTest, SharesEdgeWith) {
Rect r(2, 3, 4, 5);
@@ -422,359 +382,100 @@
EXPECT_FALSE(r.SharesEdgeWith(just_right_no_edge));
}
-// Similar to EXPECT_FLOAT_EQ, but lets NaN equal NaN
-#define EXPECT_FLOAT_AND_NAN_EQ(a, b) \
- { if (a == a || b == b) { EXPECT_FLOAT_EQ(a, b); } }
+static void TestScaleRectOverflowClamp(Rect (*function)(const Rect&,
+ float,
+ float)) {
+ // The whole rect is scaled out of kMinInt.
+ Rect xy_underflow1(-100000, -123456, 10, 20);
+ EXPECT_EQ(Rect(kMinInt, kMinInt, 0, 0),
+ function(xy_underflow1, 100000, 100000));
-TEST(RectTest, ScaleRect) {
- static const struct Test {
- int x1; // source
- int y1;
- int w1;
- int h1;
- float scale;
- float x2; // target
- float y2;
- float w2;
- float h2;
- } tests[] = {
- { 3, 3, 3, 3,
- 1.5f,
- 4.5f, 4.5f, 4.5f, 4.5f },
- { 3, 3, 3, 3,
- 0.0f,
- 0.0f, 0.0f, 0.0f, 0.0f },
- { 3, 3, 3, 3,
- std::numeric_limits<float>::quiet_NaN(),
- std::numeric_limits<float>::quiet_NaN(),
- std::numeric_limits<float>::quiet_NaN(),
- std::numeric_limits<float>::quiet_NaN(),
- std::numeric_limits<float>::quiet_NaN() },
- { 3, 3, 3, 3,
- std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max(),
- std::numeric_limits<float>::max() }
- };
+ // This rect's right/bottom is 0. The origin overflows, and is clamped to
+ // -kMaxInt (instead of kMinInt) to keep width/height not overflowing.
+ Rect xy_underflow2(-100000, -123456, 100000, 123456);
+ EXPECT_EQ(Rect(-kMaxInt, -kMaxInt, kMaxInt, kMaxInt),
+ function(xy_underflow2, 100000, 100000));
- for (size_t i = 0; i < base::size(tests); ++i) {
- RectF r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
- RectF r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
+ // A location overflow means that width/right and bottom/top also
+ // overflow so need to be clamped.
+ Rect xy_overflow(100000, 123456, 10, 20);
+ EXPECT_EQ(Rect(kMaxInt, kMaxInt, 0, 0),
+ function(xy_overflow, 100000, 100000));
- RectF scaled = ScaleRect(r1, tests[i].scale);
- EXPECT_FLOAT_AND_NAN_EQ(r2.x(), scaled.x());
- EXPECT_FLOAT_AND_NAN_EQ(r2.y(), scaled.y());
- EXPECT_FLOAT_AND_NAN_EQ(r2.width(), scaled.width());
- EXPECT_FLOAT_AND_NAN_EQ(r2.height(), scaled.height());
- }
-}
+ // In practice all rects are clamped to 0 width / 0 height so
+ // negative sizes don't matter, but try this for the sake of testing.
+ Rect size_underflow(-1, -2, 100000, 100000);
+ EXPECT_EQ(Rect(100000, 200000, 0, 0),
+ function(size_underflow, -100000, -100000));
-TEST(RectTest, ToEnclosedRect) {
- static const int max_int = std::numeric_limits<int>::max();
- static const int min_int = std::numeric_limits<int>::min();
- static const float max_float = std::numeric_limits<float>::max();
- static const float max_int_f = static_cast<float>(max_int);
- static const float min_int_f = static_cast<float>(min_int);
+ Rect size_overflow(-1, -2, 123456, 234567);
+ EXPECT_EQ(Rect(-100000, -200000, kMaxInt, kMaxInt),
+ function(size_overflow, 100000, 100000));
+ // Verify width/right gets clamped properly too if x/y positive.
+ Rect size_overflow2(1, 2, 123456, 234567);
+ EXPECT_EQ(Rect(100000, 200000, kMaxInt - 100000, kMaxInt - 200000),
+ function(size_overflow2, 100000, 100000));
- static const struct Test {
- struct {
- float x;
- float y;
- float width;
- float height;
- } in;
- struct {
- int x;
- int y;
- int width;
- int height;
- } expected;
- } tests[] = {
- {{0.0f, 0.0f, 0.0f, 0.0f}, {0, 0, 0, 0}},
- {{-1.5f, -1.5f, 3.0f, 3.0f}, {-1, -1, 2, 2}},
- {{-1.5f, -1.5f, 3.5f, 3.5f}, {-1, -1, 3, 3}},
- {{max_float, max_float, 2.0f, 2.0f}, {max_int, max_int, 0, 0}},
- {{0.0f, 0.0f, max_float, max_float}, {0, 0, max_int, max_int}},
- {{20000.5f, 20000.5f, 0.5f, 0.5f}, {20001, 20001, 0, 0}},
- {{max_int_f, max_int_f, max_int_f, max_int_f}, {max_int, max_int, 0, 0}},
- {{1.9999f, 2.0002f, 5.9998f, 6.0001f}, {2, 3, 5, 5}},
- {{1.9999f, 2.0001f, 6.0002f, 5.9998f}, {2, 3, 6, 4}},
- {{1.9998f, 2.0002f, 6.0001f, 5.9999f}, {2, 3, 5, 5}}};
+ constexpr float kMaxIntAsFloat = static_cast<float>(kMaxInt);
+ Rect max_origin_rect(kMaxInt, kMaxInt, kMaxInt, kMaxInt);
+ // width/height of max_origin_rect has already been clamped to 0.
+ EXPECT_EQ(Rect(kMaxInt, kMaxInt, 0, 0), max_origin_rect);
+ EXPECT_EQ(Rect(kMaxInt, kMaxInt, 0, 0),
+ function(max_origin_rect, kMaxIntAsFloat, kMaxIntAsFloat));
- for (size_t i = 0; i < base::size(tests); ++i) {
- RectF source(tests[i].in.x, tests[i].in.y, tests[i].in.width,
- tests[i].in.height);
- Rect enclosed = ToEnclosedRect(source);
+ Rect max_size_rect1(0, 0, kMaxInt, kMaxInt);
+ // Max sized rect can't be scaled up any further in any dimension.
+ EXPECT_EQ(max_size_rect1, function(max_size_rect1, 2, 3.5));
+ EXPECT_EQ(max_size_rect1,
+ function(max_size_rect1, kMaxIntAsFloat, kMaxIntAsFloat));
+ // Max sized ret scaled by negative scale is an empty rect.
+ EXPECT_EQ(Rect(), function(max_size_rect1, kMinInt, kMinInt));
- EXPECT_EQ(tests[i].expected.x, enclosed.x());
- EXPECT_EQ(tests[i].expected.y, enclosed.y());
- EXPECT_EQ(tests[i].expected.width, enclosed.width());
- EXPECT_EQ(tests[i].expected.height, enclosed.height());
- }
-
- {
- RectF source(min_int_f, min_int_f, max_int_f * 3.f, max_int_f * 3.f);
- Rect enclosed = ToEnclosedRect(source);
-
- // That rect can't be represented, but it should be big.
- EXPECT_EQ(max_int, enclosed.width());
- EXPECT_EQ(max_int, enclosed.height());
- // It should include some axis near the global origin.
- EXPECT_GT(1, enclosed.x());
- EXPECT_GT(1, enclosed.y());
- // And it should not cause computation issues for itself.
- EXPECT_LT(0, enclosed.right());
- EXPECT_LT(0, enclosed.bottom());
- }
-}
-
-TEST(RectTest, ToEnclosingRect) {
- static const int max_int = std::numeric_limits<int>::max();
- static const int min_int = std::numeric_limits<int>::min();
- static const float max_float = std::numeric_limits<float>::max();
- static const float epsilon_float = std::numeric_limits<float>::epsilon();
- static const float max_int_f = static_cast<float>(max_int);
- static const float min_int_f = static_cast<float>(min_int);
- static const struct Test {
- struct {
- float x;
- float y;
- float width;
- float height;
- } in;
- struct {
- int x;
- int y;
- int width;
- int height;
- } expected;
- } tests[] = {
- {{0.0f, 0.0f, 0.0f, 0.0f}, {0, 0, 0, 0}},
- {{5.5f, 5.5f, 0.0f, 0.0f}, {5, 5, 0, 0}},
- {{3.5f, 2.5f, epsilon_float, -0.0f}, {3, 2, 0, 0}},
- {{3.5f, 2.5f, 0.f, 0.001f}, {3, 2, 0, 1}},
- {{-1.5f, -1.5f, 3.0f, 3.0f}, {-2, -2, 4, 4}},
- {{-1.5f, -1.5f, 3.5f, 3.5f}, {-2, -2, 4, 4}},
- {{max_float, max_float, 2.0f, 2.0f}, {max_int, max_int, 0, 0}},
- {{0.0f, 0.0f, max_float, max_float}, {0, 0, max_int, max_int}},
- {{20000.5f, 20000.5f, 0.5f, 0.5f}, {20000, 20000, 1, 1}},
- {{max_int_f, max_int_f, max_int_f, max_int_f}, {max_int, max_int, 0, 0}},
- {{-0.5f, -0.5f, 22777712.f, 1.f}, {-1, -1, 22777713, 2}},
- {{1.9999f, 2.0002f, 5.9998f, 6.0001f}, {1, 2, 7, 7}},
- {{1.9999f, 2.0001f, 6.0002f, 5.9998f}, {1, 2, 8, 6}},
- {{1.9998f, 2.0002f, 6.0001f, 5.9999f}, {1, 2, 7, 7}}};
-
- for (size_t i = 0; i < base::size(tests); ++i) {
- RectF source(tests[i].in.x, tests[i].in.y, tests[i].in.width,
- tests[i].in.height);
-
- Rect enclosing = ToEnclosingRect(source);
- EXPECT_EQ(tests[i].expected.x, enclosing.x());
- EXPECT_EQ(tests[i].expected.y, enclosing.y());
- EXPECT_EQ(tests[i].expected.width, enclosing.width());
- EXPECT_EQ(tests[i].expected.height, enclosing.height());
- }
-
- {
- RectF source(min_int_f, min_int_f, max_int_f * 3.f, max_int_f * 3.f);
- Rect enclosing = ToEnclosingRect(source);
-
- // That rect can't be represented, but it should be big.
- EXPECT_EQ(max_int, enclosing.width());
- EXPECT_EQ(max_int, enclosing.height());
- // It should include some axis near the global origin.
- EXPECT_GT(1, enclosing.x());
- EXPECT_GT(1, enclosing.y());
- // And it should cause computation issues for itself.
- EXPECT_LT(0, enclosing.right());
- EXPECT_LT(0, enclosing.bottom());
- }
-}
-
-TEST(RectTest, ToEnclosingRectIgnoringError) {
- static const int max_int = std::numeric_limits<int>::max();
- static const float max_float = std::numeric_limits<float>::max();
- static const float epsilon_float = std::numeric_limits<float>::epsilon();
- static const float max_int_f = static_cast<float>(max_int);
- static const float error = 0.001f;
- static const struct Test {
- struct {
- float x;
- float y;
- float width;
- float height;
- } in;
- struct {
- int x;
- int y;
- int width;
- int height;
- } expected;
- } tests[] = {
- {{0.0f, 0.0f, 0.0f, 0.0f}, {0, 0, 0, 0}},
- {{5.5f, 5.5f, 0.0f, 0.0f}, {5, 5, 0, 0}},
- {{3.5f, 2.5f, epsilon_float, -0.0f}, {3, 2, 0, 0}},
- {{3.5f, 2.5f, 0.f, 0.001f}, {3, 2, 0, 1}},
- {{-1.5f, -1.5f, 3.0f, 3.0f}, {-2, -2, 4, 4}},
- {{-1.5f, -1.5f, 3.5f, 3.5f}, {-2, -2, 4, 4}},
- {{max_float, max_float, 2.0f, 2.0f}, {max_int, max_int, 0, 0}},
- {{0.0f, 0.0f, max_float, max_float}, {0, 0, max_int, max_int}},
- {{20000.5f, 20000.5f, 0.5f, 0.5f}, {20000, 20000, 1, 1}},
- {{max_int_f, max_int_f, max_int_f, max_int_f}, {max_int, max_int, 0, 0}},
- {{-0.5f, -0.5f, 22777712.f, 1.f}, {-1, -1, 22777713, 2}},
- {{1.9999f, 2.0002f, 5.9998f, 6.0001f}, {2, 2, 6, 6}},
- {{1.9999f, 2.0001f, 6.0002f, 5.9998f}, {2, 2, 6, 6}},
- {{1.9998f, 2.0002f, 6.0001f, 5.9999f}, {2, 2, 6, 6}}};
-
- for (size_t i = 0; i < base::size(tests); ++i) {
- RectF source(tests[i].in.x, tests[i].in.y, tests[i].in.width,
- tests[i].in.height);
-
- Rect enclosing = ToEnclosingRectIgnoringError(source, error);
- EXPECT_EQ(tests[i].expected.x, enclosing.x());
- EXPECT_EQ(tests[i].expected.y, enclosing.y());
- EXPECT_EQ(tests[i].expected.width, enclosing.width());
- EXPECT_EQ(tests[i].expected.height, enclosing.height());
- }
-}
-
-TEST(RectTest, ToNearestRect) {
- Rect rect;
- EXPECT_EQ(rect, ToNearestRect(RectF(rect)));
-
- rect = Rect(-1, -1, 3, 3);
- EXPECT_EQ(rect, ToNearestRect(RectF(rect)));
-
- RectF rectf(-1.00001f, -0.999999f, 3.0000001f, 2.999999f);
- EXPECT_EQ(rect, ToNearestRect(rectf));
-}
-
-TEST(RectTest, ToFlooredRect) {
- static const struct Test {
- float x1; // source
- float y1;
- float w1;
- float h1;
- int x2; // target
- int y2;
- int w2;
- int h2;
- } tests [] = {
- { 0.0f, 0.0f, 0.0f, 0.0f,
- 0, 0, 0, 0 },
- { -1.5f, -1.5f, 3.0f, 3.0f,
- -2, -2, 3, 3 },
- { -1.5f, -1.5f, 3.5f, 3.5f,
- -2, -2, 3, 3 },
- { 20000.5f, 20000.5f, 0.5f, 0.5f,
- 20000, 20000, 0, 0 },
- };
-
- for (size_t i = 0; i < base::size(tests); ++i) {
- RectF r1(tests[i].x1, tests[i].y1, tests[i].w1, tests[i].h1);
- Rect r2(tests[i].x2, tests[i].y2, tests[i].w2, tests[i].h2);
-
- Rect floored = ToFlooredRectDeprecated(r1);
- EXPECT_FLOAT_EQ(r2.x(), floored.x());
- EXPECT_FLOAT_EQ(r2.y(), floored.y());
- EXPECT_FLOAT_EQ(r2.width(), floored.width());
- EXPECT_FLOAT_EQ(r2.height(), floored.height());
- }
+ Rect max_size_rect2(-kMaxInt, -kMaxInt, kMaxInt, kMaxInt);
+ EXPECT_EQ(max_size_rect2, function(max_size_rect2, 2, 3.5));
+ EXPECT_EQ(max_size_rect2,
+ function(max_size_rect2, kMaxIntAsFloat, kMaxIntAsFloat));
+ EXPECT_EQ(Rect(kMaxInt, kMaxInt, 0, 0),
+ function(max_size_rect2, kMinInt, kMinInt));
}
TEST(RectTest, ScaleToEnclosedRect) {
- static const struct Test {
- Rect input_rect;
- float input_scale;
- Rect expected_rect;
- } tests[] = {
- {
- Rect(),
- 5.f,
- Rect(),
- }, {
- Rect(1, 1, 1, 1),
- 5.f,
- Rect(5, 5, 5, 5),
- }, {
- Rect(-1, -1, 0, 0),
- 5.f,
- Rect(-5, -5, 0, 0),
- }, {
- Rect(1, -1, 0, 1),
- 5.f,
- Rect(5, -5, 0, 5),
- }, {
- Rect(-1, 1, 1, 0),
- 5.f,
- Rect(-5, 5, 5, 0),
- }, {
- Rect(1, 2, 3, 4),
- 1.5f,
- Rect(2, 3, 4, 6),
- }, {
- Rect(-1, -2, 0, 0),
- 1.5f,
- Rect(-1, -3, 0, 0),
- }
- };
-
- for (size_t i = 0; i < base::size(tests); ++i) {
- Rect result = ScaleToEnclosedRect(tests[i].input_rect,
- tests[i].input_scale);
- EXPECT_EQ(tests[i].expected_rect, result);
- }
+ EXPECT_EQ(Rect(), ScaleToEnclosedRect(Rect(), 5.f));
+ EXPECT_EQ(Rect(5, 5, 5, 5), ScaleToEnclosedRect(Rect(1, 1, 1, 1), 5.f));
+ EXPECT_EQ(Rect(-5, -5, 0, 0), ScaleToEnclosedRect(Rect(-1, -1, 0, 0), 5.f));
+ EXPECT_EQ(Rect(5, -5, 0, 5), ScaleToEnclosedRect(Rect(1, -1, 0, 1), 5.f));
+ EXPECT_EQ(Rect(-5, 5, 5, 0), ScaleToEnclosedRect(Rect(-1, 1, 1, 0), 5.f));
+ EXPECT_EQ(Rect(2, 3, 4, 6), ScaleToEnclosedRect(Rect(1, 2, 3, 4), 1.5f));
+ EXPECT_EQ(Rect(-1, -3, 0, 0), ScaleToEnclosedRect(Rect(-1, -2, 0, 0), 1.5f));
+ EXPECT_EQ(Rect(1, 2, 2, 1), ScaleToEnclosedRect(Rect(2, 4, 9, 8), 0.3f));
+ TestScaleRectOverflowClamp(ScaleToEnclosedRect);
}
TEST(RectTest, ScaleToEnclosingRect) {
- static const struct Test {
- Rect input_rect;
- float input_scale;
- Rect expected_rect;
- } tests[] = {
- {
- Rect(),
- 5.f,
- Rect(),
- }, {
- Rect(1, 1, 1, 1),
- 5.f,
- Rect(5, 5, 5, 5),
- }, {
- Rect(-1, -1, 0, 0),
- 5.f,
- Rect(-5, -5, 0, 0),
- }, {
- Rect(1, -1, 0, 1),
- 5.f,
- Rect(5, -5, 0, 5),
- }, {
- Rect(-1, 1, 1, 0),
- 5.f,
- Rect(-5, 5, 5, 0),
- }, {
- Rect(1, 2, 3, 4),
- 1.5f,
- Rect(1, 3, 5, 6),
- }, {
- Rect(-1, -2, 0, 0),
- 1.5f,
- Rect(-2, -3, 0, 0),
- }
- };
-
- for (size_t i = 0; i < base::size(tests); ++i) {
- Rect result =
- ScaleToEnclosingRect(tests[i].input_rect, tests[i].input_scale);
- EXPECT_EQ(tests[i].expected_rect, result);
- Rect result_safe =
- ScaleToEnclosingRectSafe(tests[i].input_rect, tests[i].input_scale);
- EXPECT_EQ(tests[i].expected_rect, result_safe);
- }
+ EXPECT_EQ(Rect(), ScaleToEnclosingRect(Rect(), 5.f));
+ EXPECT_EQ(Rect(5, 5, 5, 5), ScaleToEnclosingRect(Rect(1, 1, 1, 1), 5.f));
+ EXPECT_EQ(Rect(-5, -5, 0, 0), ScaleToEnclosingRect(Rect(-1, -1, 0, 0), 5.f));
+ EXPECT_EQ(Rect(5, -5, 0, 5), ScaleToEnclosingRect(Rect(1, -1, 0, 1), 5.f));
+ EXPECT_EQ(Rect(-5, 5, 5, 0), ScaleToEnclosingRect(Rect(-1, 1, 1, 0), 5.f));
+ EXPECT_EQ(Rect(1, 3, 5, 6), ScaleToEnclosingRect(Rect(1, 2, 3, 4), 1.5f));
+ EXPECT_EQ(Rect(-2, -3, 0, 0), ScaleToEnclosingRect(Rect(-1, -2, 0, 0), 1.5f));
+ EXPECT_EQ(Rect(0, 1, 4, 3), ScaleToEnclosingRect(Rect(2, 4, 9, 8), 0.3f));
+ TestScaleRectOverflowClamp(ScaleToEnclosingRect);
}
-#if defined(OS_WIN)
+TEST(RectTest, ScaleToRoundedRect) {
+ EXPECT_EQ(Rect(), ScaleToRoundedRect(Rect(), 5.f));
+ EXPECT_EQ(Rect(5, 5, 5, 5), ScaleToRoundedRect(Rect(1, 1, 1, 1), 5.f));
+ EXPECT_EQ(Rect(-5, -5, 0, 0), ScaleToRoundedRect(Rect(-1, -1, 0, 0), 5.f));
+ EXPECT_EQ(Rect(5, -5, 0, 5), ScaleToRoundedRect(Rect(1, -1, 0, 1), 5.f));
+ EXPECT_EQ(Rect(-5, 5, 5, 0), ScaleToRoundedRect(Rect(-1, 1, 1, 0), 5.f));
+ EXPECT_EQ(Rect(2, 3, 4, 6), ScaleToRoundedRect(Rect(1, 2, 3, 4), 1.5f));
+ EXPECT_EQ(Rect(-2, -3, 0, 0), ScaleToRoundedRect(Rect(-1, -2, 0, 0), 1.5f));
+ EXPECT_EQ(Rect(1, 1, 2, 3), ScaleToRoundedRect(Rect(2, 4, 9, 8), 0.3f));
+ TestScaleRectOverflowClamp(ScaleToRoundedRect);
+}
+
+#if BUILDFLAG(IS_WIN)
TEST(RectTest, ConstructAndAssign) {
const RECT rect_1 = { 0, 0, 10, 10 };
const RECT rect_2 = { 0, 0, -10, -10 };
@@ -783,15 +484,6 @@
}
#endif
-TEST(RectTest, ToRectF) {
- // Check that explicit conversion from integer to float compiles.
- Rect a(10, 20, 30, 40);
- RectF b(10, 20, 30, 40);
-
- RectF c = RectF(a);
- EXPECT_EQ(b, c);
-}
-
TEST(RectTest, BoundingRect) {
struct {
Point a;
@@ -814,77 +506,10 @@
{ Point(-4, 6), Point(6, -4), Rect(-4, -4, 10, 10) },
};
- for (size_t i = 0; i < base::size(int_tests); ++i) {
+ for (size_t i = 0; i < std::size(int_tests); ++i) {
Rect actual = BoundingRect(int_tests[i].a, int_tests[i].b);
EXPECT_EQ(int_tests[i].expected, actual);
}
-
- struct {
- PointF a;
- PointF b;
- RectF expected;
- } float_tests[] = {
- // If point B dominates A, then A should be the origin.
- { PointF(4.2f, 6.8f), PointF(4.2f, 6.8f),
- RectF(4.2f, 6.8f, 0, 0) },
- { PointF(4.2f, 6.8f), PointF(8.5f, 6.8f),
- RectF(4.2f, 6.8f, 4.3f, 0) },
- { PointF(4.2f, 6.8f), PointF(4.2f, 9.3f),
- RectF(4.2f, 6.8f, 0, 2.5f) },
- { PointF(4.2f, 6.8f), PointF(8.5f, 9.3f),
- RectF(4.2f, 6.8f, 4.3f, 2.5f) },
- // If point A dominates B, then B should be the origin.
- { PointF(4.2f, 6.8f), PointF(4.2f, 6.8f),
- RectF(4.2f, 6.8f, 0, 0) },
- { PointF(8.5f, 6.8f), PointF(4.2f, 6.8f),
- RectF(4.2f, 6.8f, 4.3f, 0) },
- { PointF(4.2f, 9.3f), PointF(4.2f, 6.8f),
- RectF(4.2f, 6.8f, 0, 2.5f) },
- { PointF(8.5f, 9.3f), PointF(4.2f, 6.8f),
- RectF(4.2f, 6.8f, 4.3f, 2.5f) },
- // If neither point dominates, then the origin is a combination of the two.
- { PointF(4.2f, 6.8f), PointF(6.8f, 4.2f),
- RectF(4.2f, 4.2f, 2.6f, 2.6f) },
- { PointF(-4.2f, -6.8f), PointF(-6.8f, -4.2f),
- RectF(-6.8f, -6.8f, 2.6f, 2.6f) },
- { PointF(-4.2f, 6.8f), PointF(6.8f, -4.2f),
- RectF(-4.2f, -4.2f, 11.0f, 11.0f) }
- };
-
- for (size_t i = 0; i < base::size(float_tests); ++i) {
- RectF actual = BoundingRect(float_tests[i].a, float_tests[i].b);
- EXPECT_RECTF_EQ(float_tests[i].expected, actual);
- }
-}
-
-TEST(RectTest, IsExpressibleAsRect) {
- EXPECT_TRUE(RectF().IsExpressibleAsRect());
-
- float min = std::numeric_limits<int>::min();
- float max = static_cast<float>(std::numeric_limits<int>::max());
- float infinity = std::numeric_limits<float>::infinity();
-
- EXPECT_TRUE(RectF(
- min + 200, min + 200, max - 200, max - 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(
- min - 200, min + 200, max + 200, max + 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(
- min + 200 , min - 200, max + 200, max + 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(
- min + 200, min + 200, max + 200, max - 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(
- min + 200, min + 200, max - 200, max + 200).IsExpressibleAsRect());
-
- EXPECT_TRUE(RectF(0, 0, max - 200, max - 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(200, 0, max + 200, max - 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(0, 200, max - 200, max + 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(0, 0, max + 200, max - 200).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(0, 0, max - 200, max + 200).IsExpressibleAsRect());
-
- EXPECT_FALSE(RectF(infinity, 0, 1, 1).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(0, infinity, 1, 1).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(0, 0, infinity, 1).IsExpressibleAsRect());
- EXPECT_FALSE(RectF(0, 0, 1, infinity).IsExpressibleAsRect());
}
TEST(RectTest, Offset) {
@@ -901,29 +526,20 @@
i.Offset(2, -2);
EXPECT_EQ(Rect(3, 0, 3, 4), i);
- RectF f(1.1f, 2.2f, 3.3f, 4.4f);
- EXPECT_EQ(RectF(2.2f, 1.1f, 3.3f, 4.4f), (f + Vector2dF(1.1f, -1.1f)));
- EXPECT_EQ(RectF(2.2f, 1.1f, 3.3f, 4.4f), (Vector2dF(1.1f, -1.1f) + f));
- f += Vector2dF(1.1f, -1.1f);
- EXPECT_EQ(RectF(2.2f, 1.1f, 3.3f, 4.4f), f);
- EXPECT_EQ(RectF(1.1f, 2.2f, 3.3f, 4.4f), (f - Vector2dF(1.1f, -1.1f)));
- f -= Vector2dF(1.1f, -1.1f);
- EXPECT_EQ(RectF(1.1f, 2.2f, 3.3f, 4.4f), f);
+ EXPECT_EQ(Rect(kMaxInt - 2, kMaxInt - 2, 2, 2),
+ (Rect(0, 0, kMaxInt - 2, kMaxInt - 2) +
+ Vector2d(kMaxInt - 2, kMaxInt - 2)));
+ EXPECT_EQ(Rect(kMaxInt - 2, kMaxInt - 2, 2, 2),
+ (Rect(0, 0, kMaxInt - 2, kMaxInt - 2) -
+ Vector2d(2 - kMaxInt, 2 - kMaxInt)));
}
TEST(RectTest, Corners) {
Rect i(1, 2, 3, 4);
- RectF f(1.1f, 2.1f, 3.1f, 4.1f);
-
EXPECT_EQ(Point(1, 2), i.origin());
EXPECT_EQ(Point(4, 2), i.top_right());
EXPECT_EQ(Point(1, 6), i.bottom_left());
EXPECT_EQ(Point(4, 6), i.bottom_right());
-
- EXPECT_EQ(PointF(1.1f, 2.1f), f.origin());
- EXPECT_EQ(PointF(4.2f, 2.1f), f.top_right());
- EXPECT_EQ(PointF(1.1f, 6.2f), f.bottom_left());
- EXPECT_EQ(PointF(4.2f, 6.2f), f.bottom_right());
}
TEST(RectTest, Centers) {
@@ -932,23 +548,12 @@
EXPECT_EQ(Point(25, 20), i.top_center());
EXPECT_EQ(Point(40, 40), i.right_center());
EXPECT_EQ(Point(25, 60), i.bottom_center());
-
- RectF f(10.1f, 20.2f, 30.3f, 40.4f);
- EXPECT_EQ(PointF(10.1f, 40.4f), f.left_center());
- EXPECT_EQ(PointF(25.25f, 20.2f), f.top_center());
- EXPECT_EQ(PointF(40.4f, 40.4f), f.right_center());
- EXPECT_EQ(25.25f, f.bottom_center().x());
- EXPECT_NEAR(60.6f, f.bottom_center().y(), 0.001f);
}
TEST(RectTest, Transpose) {
Rect i(10, 20, 30, 40);
i.Transpose();
EXPECT_EQ(Rect(20, 10, 40, 30), i);
-
- RectF f(10.1f, 20.2f, 30.3f, 40.4f);
- f.Transpose();
- EXPECT_EQ(RectF(20.2f, 10.1f, 40.4f, 30.3f), f);
}
TEST(RectTest, ManhattanDistanceToPoint) {
@@ -964,59 +569,16 @@
EXPECT_EQ(2, i.ManhattanDistanceToPoint(Point(3, 8)));
EXPECT_EQ(2, i.ManhattanDistanceToPoint(Point(0, 7)));
EXPECT_EQ(1, i.ManhattanDistanceToPoint(Point(0, 3)));
-
- RectF f(1.1f, 2.1f, 3.1f, 4.1f);
- EXPECT_FLOAT_EQ(0.f, f.ManhattanDistanceToPoint(PointF(1.1f, 2.1f)));
- EXPECT_FLOAT_EQ(0.f, f.ManhattanDistanceToPoint(PointF(4.2f, 6.f)));
- EXPECT_FLOAT_EQ(0.f, f.ManhattanDistanceToPoint(PointF(2.f, 4.f)));
- EXPECT_FLOAT_EQ(3.2f, f.ManhattanDistanceToPoint(PointF(0.f, 0.f)));
- EXPECT_FLOAT_EQ(2.1f, f.ManhattanDistanceToPoint(PointF(2.f, 0.f)));
- EXPECT_FLOAT_EQ(2.9f, f.ManhattanDistanceToPoint(PointF(5.f, 0.f)));
- EXPECT_FLOAT_EQ(.8f, f.ManhattanDistanceToPoint(PointF(5.f, 4.f)));
- EXPECT_FLOAT_EQ(2.6f, f.ManhattanDistanceToPoint(PointF(5.f, 8.f)));
- EXPECT_FLOAT_EQ(1.8f, f.ManhattanDistanceToPoint(PointF(3.f, 8.f)));
- EXPECT_FLOAT_EQ(1.9f, f.ManhattanDistanceToPoint(PointF(0.f, 7.f)));
- EXPECT_FLOAT_EQ(1.1f, f.ManhattanDistanceToPoint(PointF(0.f, 3.f)));
}
TEST(RectTest, ManhattanInternalDistance) {
Rect i(0, 0, 400, 400);
- EXPECT_EQ(0, i.ManhattanInternalDistance(gfx::Rect(-1, 0, 2, 1)));
- EXPECT_EQ(1, i.ManhattanInternalDistance(gfx::Rect(400, 0, 1, 400)));
- EXPECT_EQ(2, i.ManhattanInternalDistance(gfx::Rect(-100, -100, 100, 100)));
- EXPECT_EQ(2, i.ManhattanInternalDistance(gfx::Rect(-101, 100, 100, 100)));
- EXPECT_EQ(4, i.ManhattanInternalDistance(gfx::Rect(-101, -101, 100, 100)));
- EXPECT_EQ(435, i.ManhattanInternalDistance(gfx::Rect(630, 603, 100, 100)));
-
- RectF f(0.0f, 0.0f, 400.0f, 400.0f);
- static const float kEpsilon = std::numeric_limits<float>::epsilon();
-
- EXPECT_FLOAT_EQ(
- 0.0f, f.ManhattanInternalDistance(gfx::RectF(-1.0f, 0.0f, 2.0f, 1.0f)));
- EXPECT_FLOAT_EQ(
- kEpsilon,
- f.ManhattanInternalDistance(gfx::RectF(400.0f, 0.0f, 1.0f, 400.0f)));
- EXPECT_FLOAT_EQ(2.0f * kEpsilon,
- f.ManhattanInternalDistance(
- gfx::RectF(-100.0f, -100.0f, 100.0f, 100.0f)));
- EXPECT_FLOAT_EQ(
- 1.0f + kEpsilon,
- f.ManhattanInternalDistance(gfx::RectF(-101.0f, 100.0f, 100.0f, 100.0f)));
- EXPECT_FLOAT_EQ(2.0f + 2.0f * kEpsilon,
- f.ManhattanInternalDistance(
- gfx::RectF(-101.0f, -101.0f, 100.0f, 100.0f)));
- EXPECT_FLOAT_EQ(
- 433.0f + 2.0f * kEpsilon,
- f.ManhattanInternalDistance(gfx::RectF(630.0f, 603.0f, 100.0f, 100.0f)));
-
- EXPECT_FLOAT_EQ(
- 0.0f, f.ManhattanInternalDistance(gfx::RectF(-1.0f, 0.0f, 1.1f, 1.0f)));
- EXPECT_FLOAT_EQ(
- 0.1f + kEpsilon,
- f.ManhattanInternalDistance(gfx::RectF(-1.5f, 0.0f, 1.4f, 1.0f)));
- EXPECT_FLOAT_EQ(
- kEpsilon,
- f.ManhattanInternalDistance(gfx::RectF(-1.5f, 0.0f, 1.5f, 1.0f)));
+ EXPECT_EQ(0, i.ManhattanInternalDistance(Rect(-1, 0, 2, 1)));
+ EXPECT_EQ(1, i.ManhattanInternalDistance(Rect(400, 0, 1, 400)));
+ EXPECT_EQ(2, i.ManhattanInternalDistance(Rect(-100, -100, 100, 100)));
+ EXPECT_EQ(2, i.ManhattanInternalDistance(Rect(-101, 100, 100, 100)));
+ EXPECT_EQ(4, i.ManhattanInternalDistance(Rect(-101, -101, 100, 100)));
+ EXPECT_EQ(435, i.ManhattanInternalDistance(Rect(630, 603, 100, 100)));
}
TEST(RectTest, IntegerOverflow) {
@@ -1084,16 +646,16 @@
// Insetting an empty rect, but the total inset (left + right) could overflow.
Rect inset_overflow;
- inset_overflow.Inset(large_number, large_number, 100, 100);
+ inset_overflow.Inset(Insets::TLBR(large_number, large_number, 100, 100));
EXPECT_EQ(large_offset, inset_overflow.origin());
- EXPECT_EQ(gfx::Size(), inset_overflow.size());
+ EXPECT_EQ(Size(), inset_overflow.size());
// Insetting where the total inset (width - left - right) could overflow.
// Also, this insetting by the min limit in all directions cannot
// represent width() without overflow, so that will also clamp.
Rect inset_overflow2;
- inset_overflow2.Inset(min_limit, min_limit, min_limit, min_limit);
- EXPECT_EQ(inset_overflow2, gfx::Rect(min_limit, min_limit, limit, limit));
+ inset_overflow2.Inset(min_limit);
+ EXPECT_EQ(inset_overflow2, Rect(min_limit, min_limit, limit, limit));
// Insetting where the width shouldn't change, but if the insets operations
// clamped in the wrong order, e.g. ((width - left) - right) vs (width - (left
@@ -1102,12 +664,12 @@
// max int anyway. Additionally, if left + right underflows, it cannot be
// increased by more then max int.
Rect inset_overflow3(0, 0, limit, limit);
- inset_overflow3.Inset(-100, -100, 100, 100);
- EXPECT_EQ(inset_overflow3, gfx::Rect(-100, -100, limit, limit));
+ inset_overflow3.Inset(Insets::TLBR(-100, -100, 100, 100));
+ EXPECT_EQ(inset_overflow3, Rect(-100, -100, limit, limit));
Rect inset_overflow4(-1000, -1000, limit, limit);
- inset_overflow4.Inset(100, 100, -100, -100);
- EXPECT_EQ(inset_overflow4, gfx::Rect(-900, -900, limit, limit));
+ inset_overflow4.Inset(Insets::TLBR(100, 100, -100, -100));
+ EXPECT_EQ(inset_overflow4, Rect(-900, -900, limit, limit));
Rect offset_overflow(0, 0, 100, 100);
offset_overflow.Offset(large_number, large_number);
@@ -1120,7 +682,7 @@
EXPECT_EQ(expected_size, operator_overflow.size());
Rect origin_maxint(limit, limit, limit, limit);
- EXPECT_EQ(origin_maxint, Rect(gfx::Point(limit, limit), gfx::Size()));
+ EXPECT_EQ(origin_maxint, Rect(Point(limit, limit), Size()));
// Expect a rect at the origin and a rect whose right/bottom is maxint
// create a rect that extends from 0..maxint in both extents.
@@ -1180,47 +742,6 @@
}
}
-TEST(RectTest, ScaleToEnclosingRectSafe) {
- constexpr int kMaxInt = std::numeric_limits<int>::max();
- constexpr int kMinInt = std::numeric_limits<int>::min();
-
- Rect xy_underflow(-100000, -123456, 10, 20);
- EXPECT_EQ(ScaleToEnclosingRectSafe(xy_underflow, 100000),
- Rect(kMinInt, kMinInt, 1000000, 2000000));
-
- // A location overflow means that width/right and bottom/top also
- // overflow so need to be clamped.
- Rect xy_overflow(100000, 123456, 10, 20);
- EXPECT_EQ(ScaleToEnclosingRectSafe(xy_overflow, 100000),
- Rect(kMaxInt, kMaxInt, 0, 0));
-
- // In practice all rects are clamped to 0 width / 0 height so
- // negative sizes don't matter, but try this for the sake of testing.
- Rect size_underflow(-1, -2, 100000, 100000);
- EXPECT_EQ(ScaleToEnclosingRectSafe(size_underflow, -100000),
- Rect(100000, 200000, 0, 0));
-
- Rect size_overflow(-1, -2, 123456, 234567);
- EXPECT_EQ(ScaleToEnclosingRectSafe(size_overflow, 100000),
- Rect(-100000, -200000, kMaxInt, kMaxInt));
- // Verify width/right gets clamped properly too if x/y positive.
- Rect size_overflow2(1, 2, 123456, 234567);
- EXPECT_EQ(ScaleToEnclosingRectSafe(size_overflow2, 100000),
- Rect(100000, 200000, kMaxInt - 100000, kMaxInt - 200000));
-
- Rect max_rect(kMaxInt, kMaxInt, kMaxInt, kMaxInt);
- EXPECT_EQ(ScaleToEnclosingRectSafe(max_rect, static_cast<float>(kMaxInt)),
- Rect(kMaxInt, kMaxInt, 0, 0));
-
- Rect min_rect(kMinInt, kMinInt, kMaxInt, kMaxInt);
- // Min rect can't be scaled up any further in any dimension.
- EXPECT_EQ(ScaleToEnclosingRectSafe(min_rect, 2, 3.5), min_rect);
- EXPECT_EQ(ScaleToEnclosingRectSafe(min_rect, static_cast<float>(kMaxInt)),
- min_rect);
- // Min rect scaled by min is an empty rect at (max, max)
- EXPECT_EQ(ScaleToEnclosingRectSafe(min_rect, kMinInt), max_rect);
-}
-
TEST(RectTest, Inset) {
Rect r(10, 20, 30, 40);
r.Inset(0);
@@ -1230,21 +751,20 @@
r.Inset(-1);
EXPECT_EQ(Rect(10, 20, 30, 40), r);
- r.Inset(1, 2);
+ r.Inset(Insets::VH(2, 1));
EXPECT_EQ(Rect(11, 22, 28, 36), r);
- r.Inset(-1, -2);
+ r.Inset(Insets::VH(-2, -1));
EXPECT_EQ(Rect(10, 20, 30, 40), r);
// The parameters are left, top, right, bottom.
- r.Inset(1, 2, 3, 4);
+ r.Inset(Insets::TLBR(2, 1, 4, 3));
EXPECT_EQ(Rect(11, 22, 26, 34), r);
- r.Inset(-1, -2, -3, -4);
+ r.Inset(Insets::TLBR(-2, -1, -4, -3));
EXPECT_EQ(Rect(10, 20, 30, 40), r);
- // Insets parameters are top, right, bottom, left.
- r.Inset(Insets(1, 2, 3, 4));
+ r.Inset(Insets::TLBR(1, 2, 3, 4));
EXPECT_EQ(Rect(12, 21, 24, 36), r);
- r.Inset(Insets(-1, -2, -3, -4));
+ r.Inset(Insets::TLBR(-1, -2, -3, -4));
EXPECT_EQ(Rect(10, 20, 30, 40), r);
}
@@ -1257,14 +777,14 @@
r.Outset(-1);
EXPECT_EQ(Rect(10, 20, 30, 40), r);
- r.Outset(1, 2);
+ r.Outset(Outsets::VH(2, 1));
EXPECT_EQ(Rect(9, 18, 32, 44), r);
- r.Outset(-1, -2);
+ r.Outset(Outsets::VH(-2, -1));
EXPECT_EQ(Rect(10, 20, 30, 40), r);
- r.Outset(1, 2, 3, 4);
+ r.Outset(Outsets::TLBR(2, 1, 4, 3));
EXPECT_EQ(Rect(9, 18, 34, 46), r);
- r.Outset(-1, -2, -3, -4);
+ r.Outset(Outsets::TLBR(-2, -1, -4, -3));
EXPECT_EQ(Rect(10, 20, 30, 40), r);
}
@@ -1275,26 +795,80 @@
r.Inset(-18);
EXPECT_EQ(Rect(10, 20, 36, 40), r);
- r.Inset(15, 30);
+ r.Inset(Insets::VH(30, 15));
EXPECT_EQ(Rect(25, 50, 6, 0), r);
- r.Inset(-15, -30);
+ r.Inset(Insets::VH(-30, -15));
EXPECT_EQ(Rect(10, 20, 36, 60), r);
- r.Inset(20, 30, 40, 50);
+ r.Inset(Insets::TLBR(30, 20, 50, 40));
EXPECT_EQ(Rect(30, 50, 0, 0), r);
- r.Inset(-20, -30, -40, -50);
+ r.Inset(Insets::TLBR(-30, -20, -50, -40));
EXPECT_EQ(Rect(10, 20, 60, 80), r);
- constexpr int kMaxInt = std::numeric_limits<int>::max();
- constexpr int kMinInt = std::numeric_limits<int>::min();
r.Outset(kMaxInt);
EXPECT_EQ(Rect(10 - kMaxInt, 20 - kMaxInt, kMaxInt, kMaxInt), r);
- r.Outset(0, kMaxInt);
+ r.Outset(Outsets().set_top_bottom(kMaxInt, kMaxInt));
EXPECT_EQ(Rect(10 - kMaxInt, kMinInt, kMaxInt, kMaxInt), r);
- r.Outset(0, kMaxInt, kMaxInt, 0);
+ r.Outset(Outsets().set_right(kMaxInt).set_top(kMaxInt));
EXPECT_EQ(Rect(10 - kMaxInt, kMinInt, kMaxInt, kMaxInt), r);
- r.Outset(kMaxInt, 0, kMaxInt, 0);
+ r.Outset(Outsets().set_left_right(kMaxInt, kMaxInt));
EXPECT_EQ(Rect(kMinInt, kMinInt, kMaxInt, kMaxInt), r);
}
+TEST(RectTest, SetByBounds) {
+ Rect r;
+ r.SetByBounds(1, 2, 30, 40);
+ EXPECT_EQ(Rect(1, 2, 29, 38), r);
+ r.SetByBounds(30, 40, 1, 2);
+ EXPECT_EQ(Rect(30, 40, 0, 0), r);
+
+ r.SetByBounds(0, 0, kMaxInt, kMaxInt);
+ EXPECT_EQ(Rect(0, 0, kMaxInt, kMaxInt), r);
+ r.SetByBounds(-1, -1, kMaxInt, kMaxInt);
+ EXPECT_EQ(Rect(-1, -1, kMaxInt, kMaxInt), r);
+ r.SetByBounds(1, 1, kMaxInt, kMaxInt);
+ EXPECT_EQ(Rect(1, 1, kMaxInt - 1, kMaxInt - 1), r);
+ r.SetByBounds(kMinInt, kMinInt, 0, 0);
+ EXPECT_EQ(Rect(kMinInt + 1, kMinInt + 1, kMaxInt, kMaxInt), r);
+ r.SetByBounds(kMinInt, kMinInt, 1, 1);
+ EXPECT_EQ(Rect(kMinInt + 2, kMinInt + 2, kMaxInt, kMaxInt), r);
+ r.SetByBounds(kMinInt, kMinInt, -1, -1);
+ EXPECT_EQ(Rect(kMinInt, kMinInt, kMaxInt, kMaxInt), r);
+ r.SetByBounds(kMinInt, kMinInt, kMaxInt, kMaxInt);
+ EXPECT_EQ(Rect(kMinInt / 2 - 1, kMinInt / 2 - 1, kMaxInt, kMaxInt), r);
+}
+
+TEST(RectTest, MaximumCoveredRect) {
+ // X aligned and intersect: unite.
+ EXPECT_EQ(Rect(10, 20, 30, 60),
+ MaximumCoveredRect(Rect(10, 20, 30, 40), Rect(10, 30, 30, 50)));
+ // X aligned and adjacent: unite.
+ EXPECT_EQ(Rect(10, 20, 30, 90),
+ MaximumCoveredRect(Rect(10, 20, 30, 40), Rect(10, 60, 30, 50)));
+ // X aligned and separate: choose the bigger one.
+ EXPECT_EQ(Rect(10, 61, 30, 50),
+ MaximumCoveredRect(Rect(10, 20, 30, 40), Rect(10, 61, 30, 50)));
+ // Y aligned and intersect: unite.
+ EXPECT_EQ(Rect(10, 20, 60, 40),
+ MaximumCoveredRect(Rect(10, 20, 30, 40), Rect(30, 20, 40, 40)));
+ // Y aligned and adjacent: unite.
+ EXPECT_EQ(Rect(10, 20, 70, 40),
+ MaximumCoveredRect(Rect(10, 20, 30, 40), Rect(40, 20, 40, 40)));
+ // Y aligned and separate: choose the bigger one.
+ EXPECT_EQ(Rect(41, 20, 40, 40),
+ MaximumCoveredRect(Rect(10, 20, 30, 40), Rect(41, 20, 40, 40)));
+ // Get the biggest expanded intersection.
+ EXPECT_EQ(Rect(0, 0, 9, 19),
+ MaximumCoveredRect(Rect(0, 0, 10, 10), Rect(0, 9, 9, 10)));
+ EXPECT_EQ(Rect(0, 0, 19, 9),
+ MaximumCoveredRect(Rect(0, 0, 10, 10), Rect(9, 0, 10, 9)));
+ // Otherwise choose the bigger one.
+ EXPECT_EQ(Rect(20, 30, 40, 50),
+ MaximumCoveredRect(Rect(10, 20, 30, 40), Rect(20, 30, 40, 50)));
+ EXPECT_EQ(Rect(10, 20, 40, 50),
+ MaximumCoveredRect(Rect(10, 20, 40, 50), Rect(20, 30, 30, 40)));
+ EXPECT_EQ(Rect(10, 20, 40, 50),
+ MaximumCoveredRect(Rect(10, 20, 40, 50), Rect(20, 30, 40, 50)));
+}
+
} // namespace gfx
diff --git a/ui/gfx/geometry/resize_utils.cc b/ui/gfx/geometry/resize_utils.cc
index 73c0ccf..9b1a0b1 100644
--- a/ui/gfx/geometry/resize_utils.cc
+++ b/ui/gfx/geometry/resize_utils.cc
@@ -1,11 +1,13 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/resize_utils.h"
+#include <algorithm>
+#include <ostream>
+
#include "base/check_op.h"
-#include "base/cxx17_backports.h"
#include "base/numerics/safe_conversions.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
@@ -30,37 +32,67 @@
} // namespace
-void SizeRectToAspectRatio(ResizeEdge resize_edge,
- float aspect_ratio,
- const Size& min_window_size,
- const Size& max_window_size,
- Rect* rect) {
+void SizeRectToAspectRatioWithExcludedMargin(
+ ResizeEdge resize_edge,
+ float aspect_ratio,
+ const Size& original_min_window_size,
+ absl::optional<Size> max_window_size,
+ const Size& excluded_margin,
+ Rect& rect) {
DCHECK_GT(aspect_ratio, 0.0f);
- DCHECK_GE(max_window_size.width(), min_window_size.width());
- DCHECK_GE(max_window_size.height(), min_window_size.height());
- DCHECK(rect->Contains(Rect(rect->origin(), min_window_size)))
- << rect->ToString() << " is smaller than the minimum size "
- << min_window_size.ToString();
- DCHECK(Rect(rect->origin(), max_window_size).Contains(*rect))
- << rect->ToString() << " is larger than the maximum size "
- << max_window_size.ToString();
+ if (max_window_size.has_value()) {
+ DCHECK_GE(max_window_size->width(), original_min_window_size.width());
+ DCHECK_GE(max_window_size->height(), original_min_window_size.height());
+ DCHECK_GE(max_window_size->width(), excluded_margin.width());
+ DCHECK_GE(max_window_size->height(), excluded_margin.height());
+ DCHECK(Rect(rect.origin(), *max_window_size).Contains(rect))
+ << rect.ToString() << " is larger than the maximum size "
+ << max_window_size->ToString();
+ }
+ DCHECK(rect.Contains(Rect(rect.origin(), original_min_window_size)))
+ << rect.ToString() << " is smaller than the minimum size "
+ << original_min_window_size.ToString();
- Size new_size = rect->size();
+ // Compute the aspect ratio with the excluded margin removed from both the
+ // rectangle and the maximum size. Note that the edge we ask for doesn't
+ // really matter; we'll position the resulting rectangle correctly later.
+ Size new_size(rect.width() - excluded_margin.width(),
+ rect.height() - excluded_margin.height());
+ if (max_window_size) {
+ max_window_size.emplace(
+ max_window_size->width() - excluded_margin.width(),
+ max_window_size->height() - excluded_margin.height());
+ }
+
+ // Also remove the margin from the minimum size, since it'll get added back at
+ // the end.
+ const Size min_window_size = original_min_window_size - excluded_margin;
+
if (IsResizingHorizontally(resize_edge)) {
new_size.set_height(base::ClampRound(new_size.width() / aspect_ratio));
if (min_window_size.height() > new_size.height() ||
- new_size.height() > max_window_size.height()) {
- new_size.set_height(base::clamp(new_size.height(),
- min_window_size.height(),
- max_window_size.height()));
+ (max_window_size.has_value() &&
+ new_size.height() > max_window_size->height())) {
+ if (max_window_size.has_value()) {
+ new_size.set_height(std::clamp(new_size.height(),
+ min_window_size.height(),
+ max_window_size->height()));
+ } else {
+ new_size.set_height(min_window_size.height());
+ }
new_size.set_width(base::ClampRound(new_size.height() * aspect_ratio));
}
} else {
new_size.set_width(base::ClampRound(new_size.height() * aspect_ratio));
if (min_window_size.width() > new_size.width() ||
- new_size.width() > max_window_size.width()) {
- new_size.set_width(base::clamp(new_size.width(), min_window_size.width(),
- max_window_size.width()));
+ (max_window_size.has_value() &&
+ new_size.width() > max_window_size->width())) {
+ if (max_window_size.has_value()) {
+ new_size.set_width(std::clamp(new_size.width(), min_window_size.width(),
+ max_window_size->width()));
+ } else {
+ new_size.set_width(min_window_size.width());
+ }
new_size.set_height(base::ClampRound(new_size.width() / aspect_ratio));
}
}
@@ -68,14 +100,22 @@
// The dimensions might still be outside of the allowed ranges at this point.
// This happens when the aspect ratio makes it impossible to fit |rect|
// within the size limits without letter-/pillarboxing.
- new_size.SetToMin(max_window_size);
+ if (max_window_size.has_value())
+ new_size.SetToMin(*max_window_size);
+
+ // The minimum size also excludes any excluded margin, so the content area has
+ // to make up the adjusted difference.
new_size.SetToMax(min_window_size);
+ // Now add the excluded margin back to the total size, so that the total size
+ // is aligned with the resize edge.
+ new_size.Enlarge(excluded_margin.width(), excluded_margin.height());
+
// |rect| bounds before sizing to aspect ratio.
- int left = rect->x();
- int top = rect->y();
- int right = rect->right();
- int bottom = rect->bottom();
+ int left = rect.x();
+ int top = rect.y();
+ int right = rect.right();
+ int bottom = rect.bottom();
switch (resize_edge) {
case ResizeEdge::kRight:
@@ -106,7 +146,17 @@
break;
}
- rect->SetByBounds(left, top, right, bottom);
+ rect.SetByBounds(left, top, right, bottom);
+}
+
+void SizeRectToAspectRatio(ResizeEdge resize_edge,
+ float aspect_ratio,
+ const Size& min_window_size,
+ absl::optional<Size> max_window_size,
+ Rect* rect) {
+ SizeRectToAspectRatioWithExcludedMargin(
+ resize_edge, aspect_ratio, min_window_size, std::move(max_window_size),
+ gfx::Size(), *rect);
}
} // namespace gfx
diff --git a/ui/gfx/geometry/resize_utils.h b/ui/gfx/geometry/resize_utils.h
index 318a31b..8804f97 100644
--- a/ui/gfx/geometry/resize_utils.h
+++ b/ui/gfx/geometry/resize_utils.h
@@ -1,10 +1,11 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_GEOMETRY_RESIZE_UTILS_H_
#define UI_GFX_GEOMETRY_RESIZE_UTILS_H_
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/geometry_export.h"
namespace gfx {
@@ -28,14 +29,27 @@
// |min_window_size| and |max_window_size| are expected to adhere to the
// given aspect ratio.
// |aspect_ratio| must be valid and is found using width / height.
-// TODO(apacible): |max_window_size| is expected to be non-empty. Handle
-// unconstrained max sizes and sizing when windows are maximized.
void GEOMETRY_EXPORT SizeRectToAspectRatio(ResizeEdge resize_edge,
float aspect_ratio,
const Size& min_window_size,
- const Size& max_window_size,
+ absl::optional<Size> max_window_size,
Rect* rect);
+// As above, but computes a size for `rect` such that it has the right aspect
+// ratio after subtracting `excluded_margin` from it. This lets the aspect
+// ratio ignore fixed borders, like a title bar. For example, if
+// `excluded_margin` is (10, 5) and `aspect_ratio` is 1.0f, then the resulting
+// rectangle might have a size of (30, 25) or (40, 35). One could use the
+// margin for drawing in the edges, and the part that's left over would have the
+// proper aspect ratio: 20/20 or 30/30, respectively.
+void GEOMETRY_EXPORT
+SizeRectToAspectRatioWithExcludedMargin(ResizeEdge resize_edge,
+ float aspect_ratio,
+ const Size& min_window_size,
+ absl::optional<Size> max_window_size,
+ const Size& excluded_margin,
+ Rect& rect);
+
} // namespace gfx
#endif // UI_GFX_GEOMETRY_RESIZE_UTILS_H_
diff --git a/ui/gfx/geometry/resize_utils_unittest.cc b/ui/gfx/geometry/resize_utils_unittest.cc
index bf1e90b..e3d80cf 100644
--- a/ui/gfx/geometry/resize_utils_unittest.cc
+++ b/ui/gfx/geometry/resize_utils_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -53,16 +53,16 @@
ResizeEdge resize_edge{};
float aspect_ratio = 0.0f;
Size min_size;
- Size max_size;
+ absl::optional<Size> max_size;
Rect input_rect;
Rect expected_output_rect;
std::string ToString() const {
- return base::StrCat({HitTestToString(resize_edge),
- " ratio=", base::NumberToString(aspect_ratio), " [",
- min_size.ToString(), "..", max_size.ToString(), "] ",
- input_rect.ToString(), " -> ",
- expected_output_rect.ToString()});
+ return base::StrCat(
+ {HitTestToString(resize_edge), " ratio=",
+ base::NumberToString(aspect_ratio), " [", min_size.ToString(), "..",
+ max_size.has_value() ? max_size->ToString() : "nullopt", "] ",
+ input_rect.ToString(), " -> ", expected_output_rect.ToString()});
}
};
@@ -75,6 +75,29 @@
EXPECT_EQ(rect, GetParam().expected_output_rect) << GetParam().ToString();
}
+TEST_P(ResizeUtilsTest, SizeRectToAspectRatioWithExcludedMargin) {
+ Rect rect = GetParam().input_rect;
+ gfx::Size excluded_margin(2, 4);
+ SizeRectToAspectRatioWithExcludedMargin(
+ GetParam().resize_edge, GetParam().aspect_ratio, GetParam().min_size,
+ GetParam().max_size, excluded_margin, rect);
+ // With excluded margin, size should have the same aspect ratio once we remove
+ // the margin.
+ gfx::Size adjusted_size = rect.size() - excluded_margin;
+ const double actual_ratio =
+ static_cast<double>(adjusted_size.width()) / adjusted_size.height();
+ // Note that all of the aspect ratios are exactly representable, so `EQ` is
+ // really expected.
+ EXPECT_EQ(actual_ratio, GetParam().aspect_ratio) << GetParam().ToString();
+ // Also verify min / max.
+ EXPECT_GE(rect.size().width(), GetParam().min_size.width());
+ EXPECT_GE(rect.size().height(), GetParam().min_size.height());
+ if (GetParam().max_size) {
+ EXPECT_LE(rect.size().width(), GetParam().max_size->width());
+ EXPECT_LE(rect.size().height(), GetParam().max_size->height());
+ }
+}
+
const SizingParams kSizeRectToSquareAspectRatioTestCases[] = {
// Dragging the top resizer up.
{ResizeEdge::kTop, kAspectRatioSquare, kMinSizeHorizontal,
@@ -121,6 +144,11 @@
kMaxSizeHorizontal,
Rect(100, 100, kMaxSizeHorizontal.height(), kMaxSizeHorizontal.height()),
Rect(100, 100, kMaxSizeHorizontal.height(), kMaxSizeHorizontal.height())},
+
+ // Dragging the top-left resizer left.
+ // No max size specified.
+ {ResizeEdge::kTopLeft, kAspectRatioSquare, kMinSizeHorizontal,
+ absl::nullopt, Rect(102, 100, 22, 24), Rect(102, 102, 22, 22)},
};
const SizingParams kSizeRectToHorizontalAspectRatioTestCases[] = {
@@ -143,6 +171,11 @@
kMaxSizeHorizontal,
Rect(100, 100, kMaxSizeHorizontal.width(), kMaxSizeHorizontal.height()),
Rect(100, 100, kMaxSizeHorizontal.width(), kMaxSizeHorizontal.height())},
+
+ // Dragging the left resizer left.
+ // No max size specified.
+ {ResizeEdge::kLeft, kAspectRatioHorizontal, kMinSizeHorizontal,
+ absl::nullopt, Rect(96, 100, 48, 22), Rect(96, 98, 48, 24)},
};
const SizingParams kSizeRectToVerticalAspectRatioTestCases[] = {
@@ -163,6 +196,11 @@
{ResizeEdge::kTop, kAspectRatioVertical, kMinSizeVertical, kMaxSizeVertical,
Rect(100, 100, kMaxSizeVertical.width(), kMaxSizeVertical.height()),
Rect(100, 100, kMaxSizeVertical.width(), kMaxSizeVertical.height())},
+
+ // Dragging the right resizer right.
+ // No max size specified.
+ {ResizeEdge::kRight, kAspectRatioVertical, kMinSizeVertical, absl::nullopt,
+ Rect(100, 100, 24, 44), Rect(100, 100, 24, 48)},
};
INSTANTIATE_TEST_SUITE_P(
diff --git a/ui/gfx/geometry/rounded_corners_f.cc b/ui/gfx/geometry/rounded_corners_f.cc
index 7db277a..4ef7a94 100644
--- a/ui/gfx/geometry/rounded_corners_f.cc
+++ b/ui/gfx/geometry/rounded_corners_f.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/rounded_corners_f.h b/ui/gfx/geometry/rounded_corners_f.h
index 12582d3..dd5aa95 100644
--- a/ui/gfx/geometry/rounded_corners_f.h
+++ b/ui/gfx/geometry/rounded_corners_f.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/rounded_corners_f_unittest.cc b/ui/gfx/geometry/rounded_corners_f_unittest.cc
index 5c9bc91..3be6ffa 100644
--- a/ui/gfx/geometry/rounded_corners_f_unittest.cc
+++ b/ui/gfx/geometry/rounded_corners_f_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/rrect_f.cc b/ui/gfx/geometry/rrect_f.cc
index ab7dece..3ecd38b 100644
--- a/ui/gfx/geometry/rrect_f.cc
+++ b/ui/gfx/geometry/rrect_f.cc
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -134,8 +134,10 @@
}
SkMatrix scale = SkMatrix::Scale(x_scale, y_scale);
SkRRect result;
- bool success = skrrect_.transform(scale, &result);
- DCHECK(success);
+ if (!skrrect_.transform(scale, &result)) {
+ skrrect_ = SkRRect::MakeEmpty();
+ return;
+ }
skrrect_ = result;
}
diff --git a/ui/gfx/geometry/rrect_f.h b/ui/gfx/geometry/rrect_f.h
index 7b3f46e..d718126 100644
--- a/ui/gfx/geometry/rrect_f.h
+++ b/ui/gfx/geometry/rrect_f.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/rrect_f_builder.cc b/ui/gfx/geometry/rrect_f_builder.cc
index 0fc1a7e..3c57079 100644
--- a/ui/gfx/geometry/rrect_f_builder.cc
+++ b/ui/gfx/geometry/rrect_f_builder.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/rrect_f_builder.h b/ui/gfx/geometry/rrect_f_builder.h
index a7c3023..3c6faf4 100644
--- a/ui/gfx/geometry/rrect_f_builder.h
+++ b/ui/gfx/geometry/rrect_f_builder.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/rrect_f_unittest.cc b/ui/gfx/geometry/rrect_f_unittest.cc
index 45eeba1..a27cf17 100644
--- a/ui/gfx/geometry/rrect_f_unittest.cc
+++ b/ui/gfx/geometry/rrect_f_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -211,8 +211,6 @@
}
TEST(RRectFTest, Scale) {
- // Note that SKRRect (the backing for RRectF) does not support scaling by NaN,
- // or scaling out of numerical bounds. So this test doesn't exercise those.
static const struct Test {
float x1; // source
float y1;
@@ -246,6 +244,22 @@
0.0f, 0.0f},
{3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f},
+ {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f, std::numeric_limits<float>::max(),
+ 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
+ {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f, 1.0f,
+ std::numeric_limits<float>::max(), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
+ {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f, std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max(), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f},
+ {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f,
+ std::numeric_limits<double>::quiet_NaN(), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f},
+ {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f, 1.0f,
+ std::numeric_limits<double>::quiet_NaN(), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f},
+ {3.0f, 4.0f, 5.0f, 6.0f, 1.0f, 1.0f,
+ std::numeric_limits<double>::quiet_NaN(),
+ std::numeric_limits<double>::quiet_NaN(), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f},
};
for (auto& test : tests) {
diff --git a/ui/gfx/geometry/size.cc b/ui/gfx/geometry/size.cc
index a7e330c..5d124f4 100644
--- a/ui/gfx/geometry/size.cc
+++ b/ui/gfx/geometry/size.cc
@@ -1,36 +1,27 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/size.h"
-#if defined(OS_WIN)
-#include <windows.h>
-#elif defined(OS_IOS)
-#include <CoreGraphics/CoreGraphics.h>
-#elif defined(OS_MAC)
-#include <ApplicationServices/ApplicationServices.h>
-#endif
-
#include "base/numerics/clamped_math.h"
#include "base/numerics/safe_math.h"
#include "base/strings/stringprintf.h"
#include "build/build_config.h"
#include "ui/gfx/geometry/size_conversions.h"
+#if BUILDFLAG(IS_WIN)
+#include <windows.h>
+#elif BUILDFLAG(IS_IOS)
+#include <CoreGraphics/CoreGraphics.h>
+#elif BUILDFLAG(IS_MAC)
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
namespace gfx {
-#if defined(OS_APPLE)
-Size::Size(const CGSize& s)
- : width_(s.width < 0 ? 0 : s.width),
- height_(s.height < 0 ? 0 : s.height) {
-}
-
-Size& Size::operator=(const CGSize& s) {
- set_width(s.width);
- set_height(s.height);
- return *this;
-}
+#if BUILDFLAG(IS_APPLE)
+Size::Size(const CGSize& s) : Size(s.width, s.height) {}
#endif
void Size::operator+=(const Size& size) {
@@ -41,14 +32,14 @@
Enlarge(-size.width(), -size.height());
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
SIZE Size::ToSIZE() const {
SIZE s;
s.cx = width();
s.cy = height();
return s;
}
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
CGSize Size::ToCGSize() const {
return CGSizeMake(width(), height());
}
@@ -70,13 +61,13 @@
}
void Size::SetToMin(const Size& other) {
- width_ = width() <= other.width() ? width() : other.width();
- height_ = height() <= other.height() ? height() : other.height();
+ width_ = std::min(width_, other.width_);
+ height_ = std::min(height_, other.height_);
}
void Size::SetToMax(const Size& other) {
- width_ = width() >= other.width() ? width() : other.width();
- height_ = height() >= other.height() ? height() : other.height();
+ width_ = std::max(width_, other.width_);
+ height_ = std::max(height_, other.height_);
}
std::string Size::ToString() const {
diff --git a/ui/gfx/geometry/size.h b/ui/gfx/geometry/size.h
index 3e5a5b6..6d7a845 100644
--- a/ui/gfx/geometry/size.h
+++ b/ui/gfx/geometry/size.h
@@ -1,39 +1,84 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_GEOMETRY_SIZE_H_
#define UI_GFX_GEOMETRY_SIZE_H_
+#include <algorithm>
#include <iosfwd>
#include <string>
-#include "base/numerics/checked_math.h"
-#include "ui/gfx/geometry/size_base.h"
-#include "ui/gfx/geometry/size_f.h"
+#include "base/numerics/safe_math.h"
+#include "build/build_config.h"
+#include "ui/gfx/geometry/geometry_export.h"
+
+#if BUILDFLAG(IS_WIN)
+typedef struct tagSIZE SIZE;
+#elif BUILDFLAG(IS_APPLE)
+typedef struct CGSize CGSize;
+#endif
namespace gfx {
// A size has width and height values.
-class Size : public SizeBase<Size, int> {
+class GEOMETRY_EXPORT Size {
public:
- Size() : SizeBase<Size, int>(0, 0) {}
- Size(int width, int height) : SizeBase<Size, int>(width, height) {}
- ~Size() {}
+ constexpr Size() : width_(0), height_(0) {}
+ constexpr Size(int width, int height)
+ : width_(std::max(0, width)), height_(std::max(0, height)) {}
+#if BUILDFLAG(IS_APPLE)
+ explicit Size(const CGSize& s);
+#endif
- operator SizeF() const {
- return SizeF(static_cast<float>(width()), static_cast<float>(height()));
+ void operator+=(const Size& size);
+
+ void operator-=(const Size& size);
+
+#if BUILDFLAG(IS_WIN)
+ SIZE ToSIZE() const;
+#elif BUILDFLAG(IS_APPLE)
+ CGSize ToCGSize() const;
+#endif
+
+ constexpr int width() const { return width_; }
+ constexpr int height() const { return height_; }
+
+ void set_width(int width) { width_ = std::max(0, width); }
+ void set_height(int height) { height_ = std::max(0, height); }
+
+ // This call will CHECK if the area of this size would overflow int.
+ int GetArea() const;
+ // Returns a checked numeric representation of the area.
+ base::CheckedNumeric<int> GetCheckedArea() const;
+
+ uint64_t Area64() const {
+ return static_cast<uint64_t>(width_) * static_cast<uint64_t>(height_);
}
- int GetArea() const { return width() * height(); }
+ void SetSize(int width, int height) {
+ set_width(width);
+ set_height(height);
+ }
- base::CheckedNumeric<int> GetCheckedArea() const {
- base::CheckedNumeric<int> checked_area = width();
- checked_area *= height();
- return checked_area;
+ void Enlarge(int grow_width, int grow_height);
+
+ void SetToMin(const Size& other);
+ void SetToMax(const Size& other);
+
+ bool IsEmpty() const { return !width() || !height(); }
+ bool IsZero() const { return !width() && !height(); }
+
+ void Transpose() {
+ using std::swap;
+ swap(width_, height_);
}
std::string ToString() const;
+
+ private:
+ int width_;
+ int height_;
};
inline bool operator==(const Size& lhs, const Size& rhs) {
@@ -44,7 +89,38 @@
return !(lhs == rhs);
}
-// extern template class SizeBase<Size, int>;
+inline Size operator+(Size lhs, const Size& rhs) {
+ lhs += rhs;
+ return lhs;
+}
+
+inline Size operator-(Size lhs, const Size& rhs) {
+ lhs -= rhs;
+ return lhs;
+}
+
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const Size& size, ::std::ostream* os);
+
+// Helper methods to scale a gfx::Size to a new gfx::Size.
+GEOMETRY_EXPORT Size ScaleToCeiledSize(const Size& size,
+ float x_scale,
+ float y_scale);
+GEOMETRY_EXPORT Size ScaleToCeiledSize(const Size& size, float scale);
+GEOMETRY_EXPORT Size ScaleToFlooredSize(const Size& size,
+ float x_scale,
+ float y_scale);
+GEOMETRY_EXPORT Size ScaleToFlooredSize(const Size& size, float scale);
+GEOMETRY_EXPORT Size ScaleToRoundedSize(const Size& size,
+ float x_scale,
+ float y_scale);
+GEOMETRY_EXPORT Size ScaleToRoundedSize(const Size& size, float scale);
+
+inline Size TransposeSize(const Size& s) {
+ return Size(s.height(), s.width());
+}
} // namespace gfx
diff --git a/ui/gfx/geometry/size_base.h b/ui/gfx/geometry/size_base.h
deleted file mode 100644
index b535b3f..0000000
--- a/ui/gfx/geometry/size_base.h
+++ /dev/null
@@ -1,57 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_GEOMETRY_SIZE_BASE_H_
-#define UI_GFX_GEOMETRY_SIZE_BASE_H_
-
-namespace gfx {
-
-// A size has width and height values.
-template <typename Class, typename Type>
-class SizeBase {
- public:
- Type width() const { return width_; }
- Type height() const { return height_; }
-
- void SetSize(Type width, Type height) {
- set_width(width);
- set_height(height);
- }
-
- void Enlarge(Type width, Type height) {
- set_width(width_ + width);
- set_height(height_ + height);
- }
-
- void set_width(Type width) { width_ = width; }
- void set_height(Type height) { height_ = height; }
-
- void SetToMin(const Class& other) {
- width_ = width_ <= other.width_ ? width_ : other.width_;
- height_ = height_ <= other.height_ ? height_ : other.height_;
- }
-
- void SetToMax(const Class& other) {
- width_ = width_ >= other.width_ ? width_ : other.width_;
- height_ = height_ >= other.height_ ? height_ : other.height_;
- }
-
- bool IsEmpty() const { return (width_ == Type(0)) || (height_ == Type(0)); }
-
- protected:
- SizeBase() {}
- SizeBase(Type width, Type height) : width_(width), height_(height) {}
-
- // Destructor is intentionally made non virtual and protected.
- // Do not make this public.
- ~SizeBase() {}
-
- private:
- Type width_;
- Type height_;
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_GEOMETRY_SIZE_BASE_H_
diff --git a/ui/gfx/geometry/size_conversions.cc b/ui/gfx/geometry/size_conversions.cc
index 18dab33..ab80bc0 100644
--- a/ui/gfx/geometry/size_conversions.cc
+++ b/ui/gfx/geometry/size_conversions.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/size_conversions.h b/ui/gfx/geometry/size_conversions.h
index 6bc74c0..29d37c0 100644
--- a/ui/gfx/geometry/size_conversions.h
+++ b/ui/gfx/geometry/size_conversions.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/size_f.cc b/ui/gfx/geometry/size_f.cc
index 6d08e18..ae43841 100644
--- a/ui/gfx/geometry/size_f.cc
+++ b/ui/gfx/geometry/size_f.cc
@@ -1,13 +1,28 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/size_f.h"
#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
+
+#if BUILDFLAG(IS_IOS)
+#include <CoreGraphics/CoreGraphics.h>
+#elif BUILDFLAG(IS_MAC)
+#include <ApplicationServices/ApplicationServices.h>
+#endif
namespace gfx {
+#if BUILDFLAG(IS_APPLE)
+SizeF::SizeF(const CGSize& size) : SizeF(size.width, size.height) {}
+
+CGSize SizeF::ToCGSize() const {
+ return CGSizeMake(width(), height());
+}
+#endif
+
float SizeF::GetArea() const {
return width() * height();
}
@@ -17,17 +32,17 @@
}
void SizeF::SetToMin(const SizeF& other) {
- width_ = width() <= other.width() ? width() : other.width();
- height_ = height() <= other.height() ? height() : other.height();
+ width_ = std::min(width_, other.width_);
+ height_ = std::min(height_, other.height_);
}
void SizeF::SetToMax(const SizeF& other) {
- width_ = width() >= other.width() ? width() : other.width();
- height_ = height() >= other.height() ? height() : other.height();
+ width_ = std::max(width_, other.width_);
+ height_ = std::max(height_, other.height_);
}
std::string SizeF::ToString() const {
- return base::StringPrintf("%fx%f", width(), height());
+ return base::StringPrintf("%gx%g", width(), height());
}
SizeF ScaleSize(const SizeF& s, float x_scale, float y_scale) {
diff --git a/ui/gfx/geometry/size_f.h b/ui/gfx/geometry/size_f.h
index 587f19e..32d329e 100644
--- a/ui/gfx/geometry/size_f.h
+++ b/ui/gfx/geometry/size_f.h
@@ -1,55 +1,149 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_GEOMETRY_SIZE_F_H_
#define UI_GFX_GEOMETRY_SIZE_F_H_
-#include <iostream>
+#include <iosfwd>
#include <string>
-#include "ui/gfx/geometry/size_base.h"
+#include "base/gtest_prod_util.h"
+#include "build/build_config.h"
+#include "ui/gfx/geometry/geometry_export.h"
+#include "ui/gfx/geometry/size.h"
+
+#if BUILDFLAG(IS_APPLE)
+struct CGSize;
+#endif
namespace gfx {
-// A floating-point version of Size.
-class SizeF : public SizeBase<SizeF, float> {
+FORWARD_DECLARE_TEST(SizeTest, TrivialDimensionTests);
+FORWARD_DECLARE_TEST(SizeTest, ClampsToZero);
+FORWARD_DECLARE_TEST(SizeTest, ConsistentClamping);
+
+// A floating version of gfx::Size.
+class GEOMETRY_EXPORT SizeF {
public:
- SizeF() : SizeBase<SizeF, float>(0, 0) {}
- SizeF(float width, float height) : SizeBase<SizeF, float>(width, height) {}
- ~SizeF() {}
+ constexpr SizeF() : width_(0.f), height_(0.f) {}
+ constexpr SizeF(float width, float height)
+ : width_(clamp(width)), height_(clamp(height)) {}
- float GetArea() const { return width() * height(); }
+ constexpr explicit SizeF(const Size& size)
+ : SizeF(static_cast<float>(size.width()),
+ static_cast<float>(size.height())) {}
- void Scale(float scale) { Scale(scale, scale); }
+#if BUILDFLAG(IS_APPLE)
+ explicit SizeF(const CGSize&);
+ CGSize ToCGSize() const;
+#endif
+
+ constexpr float width() const { return width_; }
+ constexpr float height() const { return height_; }
+
+ void set_width(float width) { width_ = clamp(width); }
+ void set_height(float height) { height_ = clamp(height); }
+
+ void operator+=(const SizeF& size) {
+ SetSize(width_ + size.width_, height_ + size.height_);
+ }
+ void operator-=(const SizeF& size) {
+ SetSize(width_ - size.width_, height_ - size.height_);
+ }
+
+ float GetArea() const;
+
+ float AspectRatio() const { return width_ / height_; }
+
+ void SetSize(float width, float height) {
+ set_width(width);
+ set_height(height);
+ }
+
+ void Enlarge(float grow_width, float grow_height);
+
+ void SetToMin(const SizeF& other);
+ void SetToMax(const SizeF& other);
+
+ // Expands width/height to the next representable value.
+ void SetToNextWidth() { width_ = next(width_); }
+ void SetToNextHeight() { height_ = next(height_); }
+
+ constexpr bool IsEmpty() const { return !width() || !height(); }
+ constexpr bool IsZero() const { return !width() && !height(); }
+
+ void Scale(float scale) {
+ Scale(scale, scale);
+ }
void Scale(float x_scale, float y_scale) {
SetSize(width() * x_scale, height() * y_scale);
}
+ // Scales the size by the inverse of the given scale (by dividing).
+ void InvScale(float inv_scale) { InvScale(inv_scale, inv_scale); }
+
+ void InvScale(float inv_x_scale, float inv_y_scale) {
+ width_ /= inv_x_scale;
+ height_ /= inv_y_scale;
+ }
+
+ void Transpose() {
+ using std::swap;
+ swap(width_, height_);
+ }
+
std::string ToString() const;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(SizeFTest, IsEmpty);
+ FRIEND_TEST_ALL_PREFIXES(SizeFTest, ClampsToZero);
+ FRIEND_TEST_ALL_PREFIXES(SizeFTest, ConsistentClamping);
+
+ static constexpr float kTrivial = 8.f * std::numeric_limits<float>::epsilon();
+
+ static constexpr float clamp(float f) { return f > kTrivial ? f : 0.f; }
+
+ static float next(float f) {
+ return std::nextafter(std::max(kTrivial, f),
+ std::numeric_limits<float>::max());
+ }
+
+ float width_;
+ float height_;
};
-inline bool operator==(const SizeF& lhs, const SizeF& rhs) {
+constexpr bool operator==(const SizeF& lhs, const SizeF& rhs) {
return lhs.width() == rhs.width() && lhs.height() == rhs.height();
}
-inline bool operator!=(const SizeF& lhs, const SizeF& rhs) {
+constexpr bool operator!=(const SizeF& lhs, const SizeF& rhs) {
return !(lhs == rhs);
}
-SizeF ScaleSize(const SizeF& p, float x_scale, float y_scale);
+inline SizeF operator+(const SizeF& lhs, const SizeF& rhs) {
+ return SizeF(lhs.width() + rhs.width(), lhs.height() + rhs.height());
+}
+
+inline SizeF operator-(const SizeF& lhs, const SizeF& rhs) {
+ return SizeF(lhs.width() - rhs.width(), lhs.height() - rhs.height());
+}
+
+GEOMETRY_EXPORT SizeF ScaleSize(const SizeF& p, float x_scale, float y_scale);
inline SizeF ScaleSize(const SizeF& p, float scale) {
return ScaleSize(p, scale, scale);
}
-inline std::ostream& operator<<(std::ostream& stream, const SizeF& size) {
- stream << "{width=" << size.width() << " height=" << size.height() << "}";
- return stream;
+inline SizeF TransposeSize(const SizeF& s) {
+ return SizeF(s.height(), s.width());
}
-// extern template class SizeBase<SizeF, float>;
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const SizeF& size, ::std::ostream* os);
} // namespace gfx
diff --git a/ui/gfx/geometry/size_f_unittest.cc b/ui/gfx/geometry/size_f_unittest.cc
new file mode 100644
index 0000000..6a4a9e4
--- /dev/null
+++ b/ui/gfx/geometry/size_f_unittest.cc
@@ -0,0 +1,214 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/size_f.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_conversions.h"
+#include "ui/gfx/geometry/test/geometry_util.h"
+
+namespace gfx {
+
+TEST(SizeFTest, SizeToSizeF) {
+ // Check that explicit conversion from integer to float compiles.
+ Size a(10, 20);
+ EXPECT_EQ(10, SizeF(a).width());
+ EXPECT_EQ(20, SizeF(a).height());
+
+ SizeF b(10, 20);
+ EXPECT_EQ(b, gfx::SizeF(a));
+}
+
+TEST(SizeFTest, ToFlooredSize) {
+ EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0, 0)));
+ EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.0001f, 0.0001f)));
+ EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.4999f, 0.4999f)));
+ EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.5f, 0.5f)));
+ EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.9999f, 0.9999f)));
+
+ EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10, 10)));
+ EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.0001f, 10.0001f)));
+ EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.4999f, 10.4999f)));
+ EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.5f, 10.5f)));
+ EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.9999f, 10.9999f)));
+}
+
+TEST(SizeFTest, ToCeiledSize) {
+ EXPECT_EQ(Size(0, 0), ToCeiledSize(SizeF(0, 0)));
+ EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.0001f, 0.0001f)));
+ EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.4999f, 0.4999f)));
+ EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.5f, 0.5f)));
+ EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.9999f, 0.9999f)));
+
+ EXPECT_EQ(Size(10, 10), ToCeiledSize(SizeF(10, 10)));
+ EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.0001f, 10.0001f)));
+ EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.4999f, 10.4999f)));
+ EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.5f, 10.5f)));
+ EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.9999f, 10.9999f)));
+}
+
+TEST(SizeFTest, ToRoundedSize) {
+ EXPECT_EQ(Size(0, 0), ToRoundedSize(SizeF(0, 0)));
+ EXPECT_EQ(Size(0, 0), ToRoundedSize(SizeF(0.0001f, 0.0001f)));
+ EXPECT_EQ(Size(0, 0), ToRoundedSize(SizeF(0.4999f, 0.4999f)));
+ EXPECT_EQ(Size(1, 1), ToRoundedSize(SizeF(0.5f, 0.5f)));
+ EXPECT_EQ(Size(1, 1), ToRoundedSize(SizeF(0.9999f, 0.9999f)));
+
+ EXPECT_EQ(Size(10, 10), ToRoundedSize(SizeF(10, 10)));
+ EXPECT_EQ(Size(10, 10), ToRoundedSize(SizeF(10.0001f, 10.0001f)));
+ EXPECT_EQ(Size(10, 10), ToRoundedSize(SizeF(10.4999f, 10.4999f)));
+ EXPECT_EQ(Size(11, 11), ToRoundedSize(SizeF(10.5f, 10.5f)));
+ EXPECT_EQ(Size(11, 11), ToRoundedSize(SizeF(10.9999f, 10.9999f)));
+}
+
+TEST(SizeFTest, SetToMinMax) {
+ SizeF a;
+
+ a = SizeF(3.5f, 5.5f);
+ EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(SizeF(2.5f, 4.5f));
+ EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(SizeF(3.5f, 5.5f));
+ EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(SizeF(4.5f, 2.5f));
+ EXPECT_EQ(SizeF(4.5f, 5.5f).ToString(), a.ToString());
+ a.SetToMax(SizeF(8.5f, 10.5f));
+ EXPECT_EQ(SizeF(8.5f, 10.5f).ToString(), a.ToString());
+
+ a.SetToMin(SizeF(9.5f, 11.5f));
+ EXPECT_EQ(SizeF(8.5f, 10.5f).ToString(), a.ToString());
+ a.SetToMin(SizeF(8.5f, 10.5f));
+ EXPECT_EQ(SizeF(8.5f, 10.5f).ToString(), a.ToString());
+ a.SetToMin(SizeF(11.5f, 9.5f));
+ EXPECT_EQ(SizeF(8.5f, 9.5f).ToString(), a.ToString());
+ a.SetToMin(SizeF(7.5f, 11.5f));
+ EXPECT_EQ(SizeF(7.5f, 9.5f).ToString(), a.ToString());
+ a.SetToMin(SizeF(3.5f, 5.5f));
+ EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
+}
+
+TEST(SizeFTest, OperatorAddSub) {
+ SizeF lhs(100.5f, 20);
+ SizeF rhs(50, 10.25f);
+
+ lhs += rhs;
+ EXPECT_EQ(SizeF(150.5f, 30.25f), lhs);
+
+ lhs = SizeF(100, 20.25f);
+ EXPECT_EQ(SizeF(150, 30.5f), lhs + rhs);
+
+ lhs = SizeF(100.5f, 20);
+ lhs -= rhs;
+ EXPECT_EQ(SizeF(50.5f, 9.75f), lhs);
+
+ lhs = SizeF(100, 20.75f);
+ EXPECT_EQ(SizeF(50, 10.5f), lhs - rhs);
+
+ EXPECT_EQ(SizeF(0, 0), rhs - lhs);
+ rhs -= lhs;
+ EXPECT_EQ(SizeF(0, 0), rhs);
+}
+
+TEST(SizeFTest, IsEmpty) {
+ const float clearly_trivial = SizeF::kTrivial / 2.f;
+ const float massize_dimension = 4e13f;
+
+ // First, using the constructor.
+ EXPECT_TRUE(SizeF(clearly_trivial, 1.f).IsEmpty());
+ EXPECT_TRUE(SizeF(.01f, clearly_trivial).IsEmpty());
+ EXPECT_TRUE(SizeF(0.f, 0.f).IsEmpty());
+ EXPECT_FALSE(SizeF(.01f, .01f).IsEmpty());
+
+ // Then use the setter.
+ SizeF test(2.f, 1.f);
+ EXPECT_FALSE(test.IsEmpty());
+
+ test.SetSize(clearly_trivial, 1.f);
+ EXPECT_TRUE(test.IsEmpty());
+
+ test.SetSize(.01f, clearly_trivial);
+ EXPECT_TRUE(test.IsEmpty());
+
+ test.SetSize(0.f, 0.f);
+ EXPECT_TRUE(test.IsEmpty());
+
+ test.SetSize(.01f, .01f);
+ EXPECT_FALSE(test.IsEmpty());
+
+ // Now just one dimension at a time.
+ test.set_width(clearly_trivial);
+ EXPECT_TRUE(test.IsEmpty());
+
+ test.set_width(massize_dimension);
+ test.set_height(clearly_trivial);
+ EXPECT_TRUE(test.IsEmpty());
+
+ test.set_width(clearly_trivial);
+ test.set_height(massize_dimension);
+ EXPECT_TRUE(test.IsEmpty());
+
+ test.set_width(2.f);
+ EXPECT_FALSE(test.IsEmpty());
+}
+
+// These are the ramifications of the decision to keep the recorded size
+// at zero for trivial sizes.
+TEST(SizeFTest, ClampsToZero) {
+ const float clearly_trivial = SizeF::kTrivial / 2.f;
+ const float nearly_trivial = SizeF::kTrivial * 1.5f;
+
+ SizeF test(clearly_trivial, 1.f);
+
+ EXPECT_FLOAT_EQ(0.f, test.width());
+ EXPECT_FLOAT_EQ(1.f, test.height());
+
+ test.SetSize(.01f, clearly_trivial);
+
+ EXPECT_FLOAT_EQ(.01f, test.width());
+ EXPECT_FLOAT_EQ(0.f, test.height());
+
+ test.SetSize(nearly_trivial, nearly_trivial);
+
+ EXPECT_FLOAT_EQ(nearly_trivial, test.width());
+ EXPECT_FLOAT_EQ(nearly_trivial, test.height());
+
+ test.Scale(0.5f);
+
+ EXPECT_FLOAT_EQ(0.f, test.width());
+ EXPECT_FLOAT_EQ(0.f, test.height());
+
+ test.SetSize(0.f, 0.f);
+ test.Enlarge(clearly_trivial, clearly_trivial);
+ test.Enlarge(clearly_trivial, clearly_trivial);
+ test.Enlarge(clearly_trivial, clearly_trivial);
+
+ EXPECT_EQ(SizeF(0.f, 0.f), test);
+}
+
+// These make sure the constructor and setter have the same effect on the
+// boundary case. This claims to know the boundary, but not which way it goes.
+TEST(SizeFTest, ConsistentClamping) {
+ SizeF resized;
+
+ resized.SetSize(SizeF::kTrivial, 0.f);
+ EXPECT_EQ(SizeF(SizeF::kTrivial, 0.f), resized);
+
+ resized.SetSize(0.f, SizeF::kTrivial);
+ EXPECT_EQ(SizeF(0.f, SizeF::kTrivial), resized);
+}
+
+TEST(SizeFTest, Transpose) {
+ gfx::SizeF s(1.5f, 2.5f);
+ EXPECT_EQ(gfx::SizeF(2.5f, 1.5f), TransposeSize(s));
+ s.Transpose();
+ EXPECT_EQ(gfx::SizeF(2.5f, 1.5f), s);
+}
+
+TEST(SizeFTest, ToString) {
+ EXPECT_EQ("1x2", SizeF(1, 2).ToString());
+ EXPECT_EQ("1.03125x2.5", SizeF(1.03125, 2.5).ToString());
+}
+
+} // namespace gfx
diff --git a/ui/gfx/geometry/size_unittest.cc b/ui/gfx/geometry/size_unittest.cc
index b3ec2ec..3b75913 100644
--- a/ui/gfx/geometry/size_unittest.cc
+++ b/ui/gfx/geometry/size_unittest.cc
@@ -1,76 +1,14 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/geometry/size_f.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
namespace gfx {
-namespace {
-
-int TestSizeF(const SizeF& s) {
- return s.width();
-}
-
-} // namespace
-
-TEST(SizeTest, ToSizeF) {
- // Check that explicit conversion from integer to float compiles.
- Size a(10, 20);
- float width = TestSizeF(gfx::SizeF(a));
- EXPECT_EQ(width, a.width());
-
- SizeF b(10, 20);
-
- EXPECT_EQ(b, gfx::SizeF(a));
-}
-
-TEST(SizeTest, ToFlooredSize) {
- EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0, 0)));
- EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.0001f, 0.0001f)));
- EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.4999f, 0.4999f)));
- EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.5f, 0.5f)));
- EXPECT_EQ(Size(0, 0), ToFlooredSize(SizeF(0.9999f, 0.9999f)));
-
- EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10, 10)));
- EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.0001f, 10.0001f)));
- EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.4999f, 10.4999f)));
- EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.5f, 10.5f)));
- EXPECT_EQ(Size(10, 10), ToFlooredSize(SizeF(10.9999f, 10.9999f)));
-}
-
-TEST(SizeTest, ToCeiledSize) {
- EXPECT_EQ(Size(0, 0), ToCeiledSize(SizeF(0, 0)));
- EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.0001f, 0.0001f)));
- EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.4999f, 0.4999f)));
- EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.5f, 0.5f)));
- EXPECT_EQ(Size(1, 1), ToCeiledSize(SizeF(0.9999f, 0.9999f)));
-
- EXPECT_EQ(Size(10, 10), ToCeiledSize(SizeF(10, 10)));
- EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.0001f, 10.0001f)));
- EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.4999f, 10.4999f)));
- EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.5f, 10.5f)));
- EXPECT_EQ(Size(11, 11), ToCeiledSize(SizeF(10.9999f, 10.9999f)));
-}
-
-TEST(SizeTest, ToRoundedSize) {
- EXPECT_EQ(Size(0, 0), ToRoundedSize(SizeF(0, 0)));
- EXPECT_EQ(Size(0, 0), ToRoundedSize(SizeF(0.0001f, 0.0001f)));
- EXPECT_EQ(Size(0, 0), ToRoundedSize(SizeF(0.4999f, 0.4999f)));
- EXPECT_EQ(Size(1, 1), ToRoundedSize(SizeF(0.5f, 0.5f)));
- EXPECT_EQ(Size(1, 1), ToRoundedSize(SizeF(0.9999f, 0.9999f)));
-
- EXPECT_EQ(Size(10, 10), ToRoundedSize(SizeF(10, 10)));
- EXPECT_EQ(Size(10, 10), ToRoundedSize(SizeF(10.0001f, 10.0001f)));
- EXPECT_EQ(Size(10, 10), ToRoundedSize(SizeF(10.4999f, 10.4999f)));
- EXPECT_EQ(Size(11, 11), ToRoundedSize(SizeF(10.5f, 10.5f)));
- EXPECT_EQ(Size(11, 11), ToRoundedSize(SizeF(10.9999f, 10.9999f)));
-}
-
-TEST(SizeTest, ClampSize) {
+TEST(SizeTest, SetToMinMax) {
Size a;
a = Size(3, 5);
@@ -96,32 +34,6 @@
EXPECT_EQ(Size(3, 5).ToString(), a.ToString());
}
-TEST(SizeTest, ClampSizeF) {
- SizeF a;
-
- a = SizeF(3.5f, 5.5f);
- EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(SizeF(2.5f, 4.5f));
- EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(SizeF(3.5f, 5.5f));
- EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(SizeF(4.5f, 2.5f));
- EXPECT_EQ(SizeF(4.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(SizeF(8.5f, 10.5f));
- EXPECT_EQ(SizeF(8.5f, 10.5f).ToString(), a.ToString());
-
- a.SetToMin(SizeF(9.5f, 11.5f));
- EXPECT_EQ(SizeF(8.5f, 10.5f).ToString(), a.ToString());
- a.SetToMin(SizeF(8.5f, 10.5f));
- EXPECT_EQ(SizeF(8.5f, 10.5f).ToString(), a.ToString());
- a.SetToMin(SizeF(11.5f, 9.5f));
- EXPECT_EQ(SizeF(8.5f, 9.5f).ToString(), a.ToString());
- a.SetToMin(SizeF(7.5f, 11.5f));
- EXPECT_EQ(SizeF(7.5f, 9.5f).ToString(), a.ToString());
- a.SetToMin(SizeF(3.5f, 5.5f));
- EXPECT_EQ(SizeF(3.5f, 5.5f).ToString(), a.ToString());
-}
-
TEST(SizeTest, Enlarge) {
Size test(3, 4);
test.Enlarge(5, -8);
@@ -153,101 +65,6 @@
EXPECT_EQ(test, min_size);
}
-// This checks that we set IsEmpty appropriately.
-TEST(SizeTest, TrivialDimensionTests) {
- const float clearly_trivial = SizeF::kTrivial / 2.f;
- const float massize_dimension = 4e13f;
-
- // First, using the constructor.
- EXPECT_TRUE(SizeF(clearly_trivial, 1.f).IsEmpty());
- EXPECT_TRUE(SizeF(.01f, clearly_trivial).IsEmpty());
- EXPECT_TRUE(SizeF(0.f, 0.f).IsEmpty());
- EXPECT_FALSE(SizeF(.01f, .01f).IsEmpty());
-
- // Then use the setter.
- SizeF test(2.f, 1.f);
- EXPECT_FALSE(test.IsEmpty());
-
- test.SetSize(clearly_trivial, 1.f);
- EXPECT_TRUE(test.IsEmpty());
-
- test.SetSize(.01f, clearly_trivial);
- EXPECT_TRUE(test.IsEmpty());
-
- test.SetSize(0.f, 0.f);
- EXPECT_TRUE(test.IsEmpty());
-
- test.SetSize(.01f, .01f);
- EXPECT_FALSE(test.IsEmpty());
-
- // Now just one dimension at a time.
- test.set_width(clearly_trivial);
- EXPECT_TRUE(test.IsEmpty());
-
- test.set_width(massize_dimension);
- test.set_height(clearly_trivial);
- EXPECT_TRUE(test.IsEmpty());
-
- test.set_width(clearly_trivial);
- test.set_height(massize_dimension);
- EXPECT_TRUE(test.IsEmpty());
-
- test.set_width(2.f);
- EXPECT_FALSE(test.IsEmpty());
-}
-
-// These are the ramifications of the decision to keep the recorded size
-// at zero for trivial sizes.
-TEST(SizeTest, ClampsToZero) {
- const float clearly_trivial = SizeF::kTrivial / 2.f;
- const float nearly_trivial = SizeF::kTrivial * 1.5f;
-
- SizeF test(clearly_trivial, 1.f);
-
- EXPECT_FLOAT_EQ(0.f, test.width());
- EXPECT_FLOAT_EQ(1.f, test.height());
-
- test.SetSize(.01f, clearly_trivial);
-
- EXPECT_FLOAT_EQ(.01f, test.width());
- EXPECT_FLOAT_EQ(0.f, test.height());
-
- test.SetSize(nearly_trivial, nearly_trivial);
-
- EXPECT_FLOAT_EQ(nearly_trivial, test.width());
- EXPECT_FLOAT_EQ(nearly_trivial, test.height());
-
- test.Scale(0.5f);
-
- EXPECT_FLOAT_EQ(0.f, test.width());
- EXPECT_FLOAT_EQ(0.f, test.height());
-
- test.SetSize(0.f, 0.f);
- test.Enlarge(clearly_trivial, clearly_trivial);
- test.Enlarge(clearly_trivial, clearly_trivial);
- test.Enlarge(clearly_trivial, clearly_trivial);
-
- EXPECT_EQ(SizeF(0.f, 0.f), test);
-}
-
-// These make sure the constructor and setter have the same effect on the
-// boundary case. This claims to know the boundary, but not which way it goes.
-TEST(SizeTest, ConsistentClamping) {
- SizeF resized;
-
- resized.SetSize(SizeF::kTrivial, 0.f);
- EXPECT_EQ(SizeF(SizeF::kTrivial, 0.f), resized);
-
- resized.SetSize(0.f, SizeF::kTrivial);
- EXPECT_EQ(SizeF(0.f, SizeF::kTrivial), resized);
-}
-
-// Let's make sure we don't unexpectedly grow the struct by adding constants.
-// Also, if some platform packs floats inefficiently, it would be worth noting.
-TEST(SizeTest, StaysSmall) {
- EXPECT_EQ(2 * sizeof(float), sizeof(SizeF));
-}
-
TEST(SizeTest, OperatorAddSub) {
Size lhs(100, 20);
Size rhs(50, 10);
@@ -297,4 +114,11 @@
EXPECT_FALSE(lhs != rhs);
}
+TEST(SizeTest, Transpose) {
+ gfx::Size s(1, 2);
+ EXPECT_EQ(gfx::Size(2, 1), TransposeSize(s));
+ s.Transpose();
+ EXPECT_EQ(gfx::Size(2, 1), s);
+}
+
} // namespace gfx
diff --git a/ui/gfx/geometry/skia_conversions.cc b/ui/gfx/geometry/skia_conversions.cc
index 72ac7b3..09e0554 100644
--- a/ui/gfx/geometry/skia_conversions.cc
+++ b/ui/gfx/geometry/skia_conversions.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,6 +9,7 @@
#include "base/numerics/safe_conversions.h"
#include "base/numerics/safe_math.h"
+#include "ui/gfx/geometry/axis_transform2d.h"
#include "ui/gfx/geometry/quad_f.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
@@ -24,18 +25,26 @@
return SkIPoint::Make(point.x(), point.y());
}
+Point SkIPointToPoint(const SkIPoint& point) {
+ return Point(point.x(), point.y());
+}
+
SkPoint PointFToSkPoint(const PointF& point) {
return SkPoint::Make(SkFloatToScalar(point.x()), SkFloatToScalar(point.y()));
}
+PointF SkPointToPointF(const SkPoint& point) {
+ return PointF(SkScalarToFloat(point.x()), SkScalarToFloat(point.y()));
+}
+
SkRect RectToSkRect(const Rect& rect) {
- return SkRect::MakeXYWH(SkIntToScalar(rect.x()), SkIntToScalar(rect.y()),
- SkIntToScalar(rect.width()),
- SkIntToScalar(rect.height()));
+ return SkRect::MakeLTRB(SkIntToScalar(rect.x()), SkIntToScalar(rect.y()),
+ SkIntToScalar(rect.right()),
+ SkIntToScalar(rect.bottom()));
}
SkIRect RectToSkIRect(const Rect& rect) {
- return SkIRect::MakeXYWH(rect.x(), rect.y(), rect.width(), rect.height());
+ return SkIRect::MakeLTRB(rect.x(), rect.y(), rect.right(), rect.bottom());
}
Rect SkIRectToRect(const SkIRect& rect) {
@@ -45,9 +54,9 @@
}
SkRect RectFToSkRect(const RectF& rect) {
- return SkRect::MakeXYWH(SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()),
- SkFloatToScalar(rect.width()),
- SkFloatToScalar(rect.height()));
+ return SkRect::MakeLTRB(SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()),
+ SkFloatToScalar(rect.right()),
+ SkFloatToScalar(rect.bottom()));
}
RectF SkRectToRectF(const SkRect& rect) {
@@ -72,25 +81,56 @@
return Size(size.width(), size.height());
}
-void TransformToFlattenedSkMatrix(const gfx::Transform& transform,
- SkMatrix* flattened) {
- // Convert from 4x4 to 3x3 by dropping the third row and column.
- flattened->set(0, transform.matrix().get(0, 0));
- flattened->set(1, transform.matrix().get(0, 1));
- flattened->set(2, transform.matrix().get(0, 3));
- flattened->set(3, transform.matrix().get(1, 0));
- flattened->set(4, transform.matrix().get(1, 1));
- flattened->set(5, transform.matrix().get(1, 3));
- flattened->set(6, transform.matrix().get(3, 0));
- flattened->set(7, transform.matrix().get(3, 1));
- flattened->set(8, transform.matrix().get(3, 3));
-}
-
-void QuadFToSkPoints(const gfx::QuadF& quad, SkPoint points[4]) {
+void QuadFToSkPoints(const QuadF& quad, SkPoint points[4]) {
points[0] = PointFToSkPoint(quad.p1());
points[1] = PointFToSkPoint(quad.p2());
points[2] = PointFToSkPoint(quad.p3());
points[3] = PointFToSkPoint(quad.p4());
}
+SkMatrix AxisTransform2dToSkMatrix(const AxisTransform2d& transform) {
+ return SkMatrix::MakeAll(
+ transform.scale().x(), 0, transform.translation().x(), // row 0
+ 0, transform.scale().y(), transform.translation().y(), // row 1
+ 0, 0, 1); // row 2
+}
+
+SkM44 TransformToSkM44(const Transform& matrix) {
+ // The parameters of this SkM44 constructor are in row-major order.
+ return SkM44(
+ matrix.rc(0, 0), matrix.rc(0, 1), matrix.rc(0, 2), matrix.rc(0, 3),
+ matrix.rc(1, 0), matrix.rc(1, 1), matrix.rc(1, 2), matrix.rc(1, 3),
+ matrix.rc(2, 0), matrix.rc(2, 1), matrix.rc(2, 2), matrix.rc(2, 3),
+ matrix.rc(3, 0), matrix.rc(3, 1), matrix.rc(3, 2), matrix.rc(3, 3));
+}
+
+Transform SkM44ToTransform(const SkM44& matrix) {
+ return Transform::RowMajor(
+ matrix.rc(0, 0), matrix.rc(0, 1), matrix.rc(0, 2), matrix.rc(0, 3),
+ matrix.rc(1, 0), matrix.rc(1, 1), matrix.rc(1, 2), matrix.rc(1, 3),
+ matrix.rc(2, 0), matrix.rc(2, 1), matrix.rc(2, 2), matrix.rc(2, 3),
+ matrix.rc(3, 0), matrix.rc(3, 1), matrix.rc(3, 2), matrix.rc(3, 3));
+}
+
+// TODO(crbug.com/1359528): Remove this function in favor of the other form.
+void TransformToFlattenedSkMatrix(const gfx::Transform& transform,
+ SkMatrix* flattened) {
+ *flattened = TransformToFlattenedSkMatrix(transform);
+}
+
+SkMatrix TransformToFlattenedSkMatrix(const Transform& matrix) {
+ // Convert from 4x4 to 3x3 by dropping row 2 (counted from 0) and column 2.
+ return SkMatrix::MakeAll(matrix.rc(0, 0), matrix.rc(0, 1), matrix.rc(0, 3),
+ matrix.rc(1, 0), matrix.rc(1, 1), matrix.rc(1, 3),
+ matrix.rc(3, 0), matrix.rc(3, 1), matrix.rc(3, 3));
+}
+
+Transform SkMatrixToTransform(const SkMatrix& matrix) {
+ return Transform::RowMajor(
+ matrix.rc(0, 0), matrix.rc(0, 1), 0, matrix.rc(0, 2), // row 0
+ matrix.rc(1, 0), matrix.rc(1, 1), 0, matrix.rc(1, 2), // row 1
+ 0, 0, 1, 0, // row 2
+ matrix.rc(2, 0), matrix.rc(2, 1), 0, matrix.rc(2, 2)); // row 3
+}
+
} // namespace gfx
diff --git a/ui/gfx/geometry/skia_conversions.h b/ui/gfx/geometry/skia_conversions.h
index a4c1329..ca1fdb9 100644
--- a/ui/gfx/geometry/skia_conversions.h
+++ b/ui/gfx/geometry/skia_conversions.h
@@ -1,11 +1,12 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_GEOMETRY_SKIA_CONVERSIONS_H_
#define UI_GFX_GEOMETRY_SKIA_CONVERSIONS_H_
-#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkM44.h"
+#include "third_party/skia/include/core/SkMatrix.h"
#include "third_party/skia/include/core/SkRect.h"
#include "ui/gfx/geometry/geometry_skia_export.h"
#include "ui/gfx/geometry/quad_f.h"
@@ -15,6 +16,7 @@
namespace gfx {
+class AxisTransform2d;
class Point;
class PointF;
class Rect;
@@ -24,7 +26,9 @@
// Convert between Skia and gfx types.
GEOMETRY_SKIA_EXPORT SkPoint PointToSkPoint(const Point& point);
GEOMETRY_SKIA_EXPORT SkIPoint PointToSkIPoint(const Point& point);
+GEOMETRY_SKIA_EXPORT Point SkIPointToPoint(const SkIPoint& point);
GEOMETRY_SKIA_EXPORT SkPoint PointFToSkPoint(const PointF& point);
+GEOMETRY_SKIA_EXPORT PointF SkPointToPointF(const SkPoint& point);
GEOMETRY_SKIA_EXPORT SkRect RectToSkRect(const Rect& rect);
GEOMETRY_SKIA_EXPORT SkIRect RectToSkIRect(const Rect& rect);
GEOMETRY_SKIA_EXPORT Rect SkIRectToRect(const SkIRect& rect);
@@ -35,12 +39,20 @@
GEOMETRY_SKIA_EXPORT SizeF SkSizeToSizeF(const SkSize& size);
GEOMETRY_SKIA_EXPORT Size SkISizeToSize(const SkISize& size);
-GEOMETRY_SKIA_EXPORT void QuadFToSkPoints(const gfx::QuadF& quad,
- SkPoint points[4]);
+GEOMETRY_SKIA_EXPORT void QuadFToSkPoints(const QuadF& quad, SkPoint points[4]);
+GEOMETRY_SKIA_EXPORT SkMatrix
+AxisTransform2dToSkMatrix(const AxisTransform2d& transform);
+
+GEOMETRY_SKIA_EXPORT SkM44 TransformToSkM44(const Transform& tranform);
+GEOMETRY_SKIA_EXPORT Transform SkM44ToTransform(const SkM44& matrix);
+// TODO(crbug.com/1359528): Remove this function in favor of the other form.
GEOMETRY_SKIA_EXPORT void TransformToFlattenedSkMatrix(
const gfx::Transform& transform,
SkMatrix* flattened);
+GEOMETRY_SKIA_EXPORT SkMatrix
+TransformToFlattenedSkMatrix(const Transform& transform);
+GEOMETRY_SKIA_EXPORT Transform SkMatrixToTransform(const SkMatrix& matrix);
} // namespace gfx
diff --git a/ui/gfx/geometry/skia_conversions_unittest.cc b/ui/gfx/geometry/skia_conversions_unittest.cc
new file mode 100644
index 0000000..cd350eb
--- /dev/null
+++ b/ui/gfx/geometry/skia_conversions_unittest.cc
@@ -0,0 +1,89 @@
+// Copyright 2013 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/skia_conversions.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/transform.h"
+
+namespace gfx {
+
+TEST(SkiaConversionsTest, SkiaRectConversions) {
+ Rect isrc(10, 20, 30, 40);
+ RectF fsrc(10.5f, 20.5f, 30.5f, 40.5f);
+
+ SkIRect skirect = RectToSkIRect(isrc);
+ EXPECT_EQ(isrc.ToString(), SkIRectToRect(skirect).ToString());
+
+ SkRect skrect = RectToSkRect(isrc);
+ EXPECT_EQ(gfx::RectF(isrc).ToString(), SkRectToRectF(skrect).ToString());
+
+ skrect = RectFToSkRect(fsrc);
+ EXPECT_EQ(fsrc.ToString(), SkRectToRectF(skrect).ToString());
+}
+
+TEST(SkiaConversionsTest, RectToSkRectAccuracy) {
+ // For a gfx::Rect with large negative x/y and large with/height, but small
+ // right/bottom, we expect the converted SkRect has accurate right/bottom,
+ // to make sure the right/bottom edge, which is likely to be visible, to be
+ // rendered correctly.
+ Rect r;
+ for (int i = 0; i < 50; i++) {
+ r.SetByBounds(-30000000, -28000000, i, i + 1);
+ EXPECT_EQ(i, r.right());
+ EXPECT_EQ(i + 1, r.bottom());
+ SkRect skrect = RectToSkRect(r);
+ EXPECT_EQ(i, skrect.right());
+ EXPECT_EQ(i + 1, skrect.bottom());
+ }
+}
+
+TEST(SkiaConversionsTest, SkIRectToRectClamping) {
+ // This clamping only makes sense if SkIRect and gfx::Rect have the same size.
+ // Otherwise, either other overflows can occur that we don't handle, or no
+ // overflows can ocur.
+ if (sizeof(int) != sizeof(int32_t))
+ return;
+ using Limits = std::numeric_limits<int>;
+
+ // right-left and bottom-top would overflow.
+ // These should be mapped to max width/height, which is as close as gfx::Rect
+ // can represent.
+ Rect result = SkIRectToRect(SkIRect::MakeLTRB(Limits::min(), Limits::min(),
+ Limits::max(), Limits::max()));
+ EXPECT_EQ(gfx::Size(Limits::max(), Limits::max()), result.size());
+
+ // right-left and bottom-top would underflow.
+ // These should be mapped to zero, like all negative values.
+ result = SkIRectToRect(SkIRect::MakeLTRB(Limits::max(), Limits::max(),
+ Limits::min(), Limits::min()));
+ EXPECT_EQ(gfx::Rect(Limits::max(), Limits::max(), 0, 0), result);
+}
+
+TEST(SkiaConversionsTest, TransformSkM44Conversions) {
+ std::vector<float> v = {1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16};
+ Transform t = Transform::ColMajorF(v.data());
+
+ SkM44 m = TransformToSkM44(t);
+ std::vector<float> v1(16);
+ m.getColMajor(v1.data());
+ EXPECT_EQ(v, v1);
+ EXPECT_EQ(t, SkM44ToTransform(m));
+}
+
+TEST(SkiaConversionsTest, TransformSkMatrixConversions) {
+ std::vector<float> v = {1, 2, 0, 4, 5, 6, 0, 8, 0, 0, 1, 0, 13, 14, 0, 16};
+ Transform t = Transform::ColMajorF(v.data());
+
+ std::vector<float> v1(16);
+ SkMatrix m = TransformToFlattenedSkMatrix(t);
+ SkM44 m44(m);
+ m44.getColMajor(v1.data());
+ EXPECT_EQ(v, v1);
+ EXPECT_EQ(t, SkMatrixToTransform(m));
+}
+
+} // namespace gfx
diff --git a/ui/gfx/geometry/test/fuzzer_util.cc b/ui/gfx/geometry/test/fuzzer_util.cc
new file mode 100644
index 0000000..9ceaf81
--- /dev/null
+++ b/ui/gfx/geometry/test/fuzzer_util.cc
@@ -0,0 +1,26 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/test/fuzzer_util.h"
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <vector>
+
+#include "base/check_op.h"
+#include "ui/gfx/geometry/transform.h"
+
+namespace gfx {
+
+Transform ConsumeTransform(FuzzedDataProvider& fuzz) {
+ Transform transform;
+ float matrix_data[16];
+ if (fuzz.ConsumeBool() && fuzz.remaining_bytes() >= sizeof(matrix_data)) {
+ size_t consumed = fuzz.ConsumeData(matrix_data, sizeof(matrix_data));
+ CHECK_EQ(consumed, sizeof(matrix_data));
+ transform = Transform::ColMajorF(matrix_data);
+ }
+ return transform;
+}
+
+} // namespace gfx
diff --git a/ui/gfx/geometry/test/fuzzer_util.h b/ui/gfx/geometry/test/fuzzer_util.h
new file mode 100644
index 0000000..6f40b4d
--- /dev/null
+++ b/ui/gfx/geometry/test/fuzzer_util.h
@@ -0,0 +1,20 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_TEST_FUZZER_UTIL_H_
+#define UI_GFX_GEOMETRY_TEST_FUZZER_UTIL_H_
+
+#include "ui/gfx/geometry/transform.h"
+
+class FuzzedDataProvider;
+
+namespace gfx {
+
+class Transform;
+
+Transform ConsumeTransform(FuzzedDataProvider&);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_TEST_FUZZER_UTIL_H_
diff --git a/ui/gfx/geometry/test/geometry_util.cc b/ui/gfx/geometry/test/geometry_util.cc
new file mode 100644
index 0000000..502f2df
--- /dev/null
+++ b/ui/gfx/geometry/test/geometry_util.cc
@@ -0,0 +1,512 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/test/geometry_util.h"
+
+#include <sstream>
+#include <string>
+
+#include "base/strings/stringprintf.h"
+#include "ui/gfx/geometry/axis_transform2d.h"
+#include "ui/gfx/geometry/box_f.h"
+#include "ui/gfx/geometry/decomposed_transform.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/insets_f.h"
+#include "ui/gfx/geometry/mask_filter_info.h"
+#include "ui/gfx/geometry/outsets.h"
+#include "ui/gfx/geometry/outsets_f.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point3_f.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/quad_f.h"
+#include "ui/gfx/geometry/quaternion.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/geometry/skia_conversions.h"
+#include "ui/gfx/geometry/transform.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+#include "ui/gfx/selection_bound.h"
+
+namespace gfx {
+
+namespace {
+
+bool FloatAlmostEqual(float a, float b) {
+ // FloatLE is the gtest predicate for less than or almost equal to.
+ return ::testing::FloatLE("a", "b", a, b) &&
+ ::testing::FloatLE("b", "a", b, a);
+}
+
+bool FloatNear(float a, float b, float abs_error) {
+ return std::abs(a - b) <= abs_error;
+}
+
+template <typename T>
+::testing::AssertionResult EqFailure(const char* lhs_expr,
+ const char* rhs_expr,
+ const T& lhs,
+ const T& rhs) {
+ return ::testing::AssertionFailure()
+ << "Expected equality of these values:\n"
+ << lhs_expr << "\n Which is: " << lhs.ToString() << "\n"
+ << rhs_expr << "\n Which is: " << rhs.ToString();
+}
+
+template <typename T>
+::testing::AssertionResult NearFailure(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const T& lhs,
+ const T& rhs,
+ float abs_error) {
+ return ::testing::AssertionFailure()
+ << "The difference between these values:\n"
+ << lhs_expr << "\n Which is: " << lhs.ToString() << "\n"
+ << rhs_expr << "\n Which is: " << rhs.ToString() << "\nexceeds "
+ << abs_error_expr << "\n Which is: " << abs_error;
+}
+
+struct SkRectToString {
+ SkRect r;
+ std::string ToString() const {
+ return base::StringPrintf("SkRect::MakeLTRB(%g, %g, %g, %g)", r.left(),
+ r.top(), r.right(), r.bottom());
+ }
+};
+
+} // namespace
+
+::testing::AssertionResult AssertAxisTransform2dFloatEqual(
+ const char* lhs_expr,
+ const char* rhs_expr,
+ const AxisTransform2d& lhs,
+ const AxisTransform2d& rhs) {
+ if (FloatAlmostEqual(lhs.scale().x(), rhs.scale().x()) &&
+ FloatAlmostEqual(lhs.scale().y(), rhs.scale().y()) &&
+ FloatAlmostEqual(lhs.translation().x(), rhs.translation().x()) &&
+ FloatAlmostEqual(lhs.translation().y(), rhs.translation().y())) {
+ return ::testing::AssertionSuccess();
+ }
+ return EqFailure(lhs_expr, rhs_expr, lhs, rhs);
+}
+
+::testing::AssertionResult AssertQuaternionFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const Quaternion& lhs,
+ const Quaternion& rhs) {
+ if (FloatAlmostEqual(lhs.x(), rhs.x()) &&
+ FloatAlmostEqual(lhs.y(), rhs.y()) &&
+ FloatAlmostEqual(lhs.z(), rhs.z()) &&
+ FloatAlmostEqual(lhs.w(), rhs.w())) {
+ return ::testing::AssertionSuccess();
+ }
+ return EqFailure(lhs_expr, rhs_expr, lhs, rhs);
+}
+
+::testing::AssertionResult AssertQuaternionFloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const Quaternion& lhs,
+ const Quaternion& rhs,
+ float abs_error) {
+ if (FloatNear(lhs.x(), rhs.x(), abs_error) &&
+ FloatNear(lhs.y(), rhs.y(), abs_error) &&
+ FloatNear(lhs.z(), rhs.z(), abs_error) &&
+ FloatNear(lhs.w(), rhs.w(), abs_error)) {
+ return ::testing::AssertionSuccess();
+ }
+ return NearFailure(lhs_expr, rhs_expr, abs_error_expr, lhs, rhs, abs_error);
+}
+
+::testing::AssertionResult AssertDecomposedTransformFloatEqual(
+ const char* lhs_expr,
+ const char* rhs_expr,
+ const DecomposedTransform& lhs,
+ const DecomposedTransform& rhs) {
+#define CHECK_ARRAY(array) \
+ do { \
+ for (size_t i = 0; i < std::size(lhs.array); i++) { \
+ if (!FloatAlmostEqual(lhs.array[i], rhs.array[i])) { \
+ return EqFailure(lhs_expr, rhs_expr, lhs, rhs) \
+ << "First difference is at: " << #array << "[" << i << "]"; \
+ } \
+ } \
+ } while (false)
+
+ CHECK_ARRAY(translate);
+ CHECK_ARRAY(scale);
+ CHECK_ARRAY(skew);
+ CHECK_ARRAY(perspective);
+#undef CHECK_ARRAY
+
+ return AssertQuaternionFloatEqual(lhs_expr, rhs_expr, lhs.quaternion,
+ rhs.quaternion)
+ << " In quaternion";
+}
+
+::testing::AssertionResult AssertDecomposedTransformFloatNear(
+ const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const DecomposedTransform& lhs,
+ const DecomposedTransform& rhs,
+ float abs_error) {
+#define CHECK_ARRAY(array) \
+ do { \
+ for (size_t i = 0; i < std::size(lhs.array); i++) { \
+ if (!FloatNear(lhs.array[i], rhs.array[i], abs_error)) { \
+ return NearFailure(lhs_expr, rhs_expr, abs_error_expr, lhs, rhs, \
+ abs_error) \
+ << "First difference is at: " << #array << "[" << i << "]"; \
+ } \
+ } \
+ } while (false)
+
+ CHECK_ARRAY(translate);
+ CHECK_ARRAY(scale);
+ CHECK_ARRAY(skew);
+ CHECK_ARRAY(perspective);
+#undef CHECK_ARRAY
+
+ return AssertQuaternionFloatNear(lhs_expr, rhs_expr, abs_error_expr,
+ lhs.quaternion, rhs.quaternion, abs_error)
+ << " In quaternion";
+}
+
+::testing::AssertionResult AssertTransformFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const Transform& lhs,
+ const Transform& rhs) {
+ for (int row = 0; row < 4; ++row) {
+ for (int col = 0; col < 4; ++col) {
+ if (!FloatAlmostEqual(lhs.rc(row, col), rhs.rc(row, col))) {
+ return EqFailure(lhs_expr, rhs_expr, lhs, rhs)
+ << "\nFirst difference at row: " << row << " col: " << col;
+ }
+ }
+ }
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult AssertTransformFloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const Transform& lhs,
+ const Transform& rhs,
+ float abs_error) {
+ for (int row = 0; row < 4; ++row) {
+ for (int col = 0; col < 4; ++col) {
+ if (!FloatNear(lhs.rc(row, col), rhs.rc(row, col), abs_error)) {
+ return NearFailure(lhs_expr, rhs_expr, abs_error_expr, lhs, rhs,
+ abs_error)
+ << "\nFirst difference at row: " << row << " col: " << col;
+ }
+ }
+ }
+ return ::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult AssertBoxFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const BoxF& lhs,
+ const BoxF& rhs) {
+ if (FloatAlmostEqual(lhs.x(), rhs.x()) &&
+ FloatAlmostEqual(lhs.y(), rhs.y()) &&
+ FloatAlmostEqual(lhs.z(), rhs.z()) &&
+ FloatAlmostEqual(lhs.width(), rhs.width()) &&
+ FloatAlmostEqual(lhs.height(), rhs.height()) &&
+ FloatAlmostEqual(lhs.depth(), rhs.depth())) {
+ return ::testing::AssertionSuccess();
+ }
+ return EqFailure(lhs_expr, rhs_expr, lhs, rhs);
+}
+
+::testing::AssertionResult AssertBoxFloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const BoxF& lhs,
+ const BoxF& rhs,
+ float abs_error) {
+ if (FloatNear(lhs.x(), rhs.x(), abs_error) &&
+ FloatNear(lhs.y(), rhs.y(), abs_error) &&
+ FloatNear(lhs.z(), rhs.z(), abs_error) &&
+ FloatNear(lhs.width(), rhs.width(), abs_error) &&
+ FloatNear(lhs.height(), rhs.height(), abs_error) &&
+ FloatNear(lhs.depth(), rhs.depth(), abs_error)) {
+ return ::testing::AssertionSuccess();
+ }
+ return NearFailure(lhs_expr, rhs_expr, abs_error_expr, lhs, rhs, abs_error);
+}
+
+::testing::AssertionResult AssertPointFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const PointF& lhs,
+ const PointF& rhs) {
+ if (FloatAlmostEqual(lhs.x(), rhs.x()) &&
+ FloatAlmostEqual(lhs.y(), rhs.y())) {
+ return ::testing::AssertionSuccess();
+ }
+ return EqFailure(lhs_expr, rhs_expr, lhs, rhs);
+}
+
+::testing::AssertionResult AssertPointFloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const PointF& lhs,
+ const PointF& rhs,
+ float abs_error) {
+ if (FloatNear(lhs.x(), rhs.x(), abs_error) &&
+ FloatNear(lhs.y(), rhs.y(), abs_error)) {
+ return ::testing::AssertionSuccess();
+ }
+ return NearFailure(lhs_expr, rhs_expr, abs_error_expr, lhs, rhs, abs_error);
+}
+
+::testing::AssertionResult AssertPoint3FloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const Point3F& lhs,
+ const Point3F& rhs) {
+ if (FloatAlmostEqual(lhs.x(), rhs.x()) &&
+ FloatAlmostEqual(lhs.y(), rhs.y()) &&
+ FloatAlmostEqual(lhs.z(), rhs.z())) {
+ return ::testing::AssertionSuccess();
+ }
+ return EqFailure(lhs_expr, rhs_expr, lhs, rhs);
+}
+
+::testing::AssertionResult AssertPoint3FloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const Point3F& lhs,
+ const Point3F& rhs,
+ float abs_error) {
+ if (FloatNear(lhs.x(), rhs.x(), abs_error) &&
+ FloatNear(lhs.y(), rhs.y(), abs_error) &&
+ FloatNear(lhs.z(), rhs.z(), abs_error)) {
+ return ::testing::AssertionSuccess();
+ }
+ return NearFailure(lhs_expr, rhs_expr, abs_error_expr, lhs, rhs, abs_error);
+}
+
+::testing::AssertionResult AssertVector2dFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const Vector2dF& lhs,
+ const Vector2dF& rhs) {
+ if (FloatAlmostEqual(lhs.x(), rhs.x()) &&
+ FloatAlmostEqual(lhs.y(), rhs.y())) {
+ return ::testing::AssertionSuccess();
+ }
+ return EqFailure(lhs_expr, rhs_expr, lhs, rhs);
+}
+
+::testing::AssertionResult AssertVector2dFloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const Vector2dF& lhs,
+ const Vector2dF& rhs,
+ float abs_error) {
+ if (FloatNear(lhs.x(), rhs.x(), abs_error) &&
+ FloatNear(lhs.y(), rhs.y(), abs_error)) {
+ return ::testing::AssertionSuccess();
+ }
+ return NearFailure(lhs_expr, rhs_expr, abs_error_expr, lhs, rhs, abs_error);
+}
+
+::testing::AssertionResult AssertVector3dFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const Vector3dF& lhs,
+ const Vector3dF& rhs) {
+ if (FloatAlmostEqual(lhs.x(), rhs.x()) &&
+ FloatAlmostEqual(lhs.y(), rhs.y()) &&
+ FloatAlmostEqual(lhs.z(), rhs.z())) {
+ return ::testing::AssertionSuccess();
+ }
+ return EqFailure(lhs_expr, rhs_expr, lhs, rhs);
+}
+
+::testing::AssertionResult AssertVector3dFloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const Vector3dF& lhs,
+ const Vector3dF& rhs,
+ float abs_error) {
+ if (FloatNear(lhs.x(), rhs.x(), abs_error) &&
+ FloatNear(lhs.y(), rhs.y(), abs_error) &&
+ FloatNear(lhs.z(), rhs.z(), abs_error)) {
+ return ::testing::AssertionSuccess();
+ }
+ return NearFailure(lhs_expr, rhs_expr, abs_error_expr, lhs, rhs, abs_error);
+}
+
+::testing::AssertionResult AssertRectFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const RectF& lhs,
+ const RectF& rhs) {
+ if (FloatAlmostEqual(lhs.x(), rhs.x()) &&
+ FloatAlmostEqual(lhs.y(), rhs.y()) &&
+ FloatAlmostEqual(lhs.width(), rhs.width()) &&
+ FloatAlmostEqual(lhs.height(), rhs.height())) {
+ return ::testing::AssertionSuccess();
+ }
+ return EqFailure(lhs_expr, rhs_expr, lhs, rhs);
+}
+
+::testing::AssertionResult AssertRectFloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const RectF& lhs,
+ const RectF& rhs,
+ float abs_error) {
+ if (FloatNear(lhs.x(), rhs.x(), abs_error) &&
+ FloatNear(lhs.y(), rhs.y(), abs_error) &&
+ FloatNear(lhs.width(), rhs.width(), abs_error) &&
+ FloatNear(lhs.height(), rhs.height(), abs_error)) {
+ return ::testing::AssertionSuccess();
+ }
+ return NearFailure(lhs_expr, rhs_expr, abs_error_expr, lhs, rhs, abs_error);
+}
+
+::testing::AssertionResult AssertSkRectFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const SkRect& lhs,
+ const SkRect& rhs) {
+ if (FloatAlmostEqual(lhs.x(), rhs.x()) &&
+ FloatAlmostEqual(lhs.y(), rhs.y()) &&
+ FloatAlmostEqual(lhs.right(), rhs.right()) &&
+ FloatAlmostEqual(lhs.bottom(), rhs.bottom())) {
+ return ::testing::AssertionSuccess();
+ }
+ return EqFailure(lhs_expr, rhs_expr, SkRectToString{lhs},
+ SkRectToString{rhs});
+}
+
+::testing::AssertionResult AssertSizeFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const SizeF& lhs,
+ const SizeF& rhs) {
+ if (FloatAlmostEqual(lhs.width(), rhs.width()) &&
+ FloatAlmostEqual(lhs.height(), rhs.height())) {
+ return ::testing::AssertionSuccess();
+ }
+ return EqFailure(lhs_expr, rhs_expr, lhs, rhs);
+}
+
+::testing::AssertionResult AssertSkSizeFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const SkSize& lhs,
+ const SkSize& rhs) {
+ return AssertSizeFloatEqual(lhs_expr, rhs_expr, SkSizeToSizeF(lhs),
+ SkSizeToSizeF(rhs));
+}
+
+::testing::AssertionResult AssertInsetsFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const InsetsF& lhs,
+ const InsetsF& rhs) {
+ if (FloatAlmostEqual(lhs.top(), rhs.top()) &&
+ FloatAlmostEqual(lhs.right(), rhs.right()) &&
+ FloatAlmostEqual(lhs.bottom(), rhs.bottom()) &&
+ FloatAlmostEqual(lhs.left(), rhs.left())) {
+ return ::testing::AssertionSuccess();
+ }
+ return EqFailure(lhs_expr, rhs_expr, lhs, rhs);
+}
+
+void PrintTo(const AxisTransform2d& transform, ::std::ostream* os) {
+ *os << transform.ToString();
+}
+
+void PrintTo(const BoxF& box, ::std::ostream* os) {
+ *os << box.ToString();
+}
+
+void PrintTo(const Point& point, ::std::ostream* os) {
+ *os << point.ToString();
+}
+
+void PrintTo(const Point3F& point, ::std::ostream* os) {
+ *os << point.ToString();
+}
+
+void PrintTo(const PointF& point, ::std::ostream* os) {
+ *os << point.ToString();
+}
+
+void PrintTo(const Insets& input, ::std::ostream* os) {
+ *os << input.ToString();
+}
+
+void PrintTo(const InsetsF& input, ::std::ostream* os) {
+ *os << input.ToString();
+}
+
+void PrintTo(const Outsets& input, ::std::ostream* os) {
+ *os << input.ToString();
+}
+
+void PrintTo(const OutsetsF& input, ::std::ostream* os) {
+ *os << input.ToString();
+}
+
+void PrintTo(const QuadF& quad, ::std::ostream* os) {
+ *os << quad.ToString();
+}
+
+void PrintTo(const Rect& rect, ::std::ostream* os) {
+ *os << rect.ToString();
+}
+
+void PrintTo(const RectF& rect, ::std::ostream* os) {
+ *os << rect.ToString();
+}
+
+void PrintTo(const Size& size, ::std::ostream* os) {
+ *os << size.ToString();
+}
+
+void PrintTo(const SizeF& size, ::std::ostream* os) {
+ *os << size.ToString();
+}
+
+void PrintTo(const Transform& transform, ::std::ostream* os) {
+ *os << transform.ToString();
+}
+
+void PrintTo(const Vector2d& vector, ::std::ostream* os) {
+ *os << vector.ToString();
+}
+
+void PrintTo(const Vector2dF& vector, ::std::ostream* os) {
+ *os << vector.ToString();
+}
+
+void PrintTo(const Vector3dF& vector, ::std::ostream* os) {
+ *os << vector.ToString();
+}
+
+void PrintTo(const MaskFilterInfo& info, ::std::ostream* os) {
+ *os << info.ToString();
+}
+
+void PrintTo(const SelectionBound& bound, ::std::ostream* os) {
+ *os << bound.ToString();
+}
+
+void PrintTo(const SkRect& rect, ::std::ostream* os) {
+ *os << SkRectToString{rect}.ToString();
+}
+
+void PrintTo(const DecomposedTransform& transform, ::std::ostream* os) {
+ *os << transform.ToString();
+}
+
+void PrintTo(const Quaternion& quaternion, ::std::ostream* os) {
+ *os << quaternion.ToString();
+}
+
+} // namespace gfx
diff --git a/ui/gfx/geometry/test/geometry_util.h b/ui/gfx/geometry/test/geometry_util.h
new file mode 100644
index 0000000..57968ba
--- /dev/null
+++ b/ui/gfx/geometry/test/geometry_util.h
@@ -0,0 +1,248 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_TEST_GEOMETRY_UTIL_H_
+#define UI_GFX_GEOMETRY_TEST_GEOMETRY_UTIL_H_
+
+#include <iosfwd>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+struct SkRect;
+struct SkSize;
+
+namespace gfx {
+
+class AxisTransform2d;
+class BoxF;
+class InsetsF;
+class PointF;
+class Point3F;
+class Quaternion;
+class RectF;
+class SizeF;
+class Transform;
+class Vector2dF;
+class Vector3dF;
+struct DecomposedTransform;
+
+// This file defines gtest macros for floating-point geometry types. The
+// difference from EXPECT_EQ is that each floating-point value is checked with
+// something equivalent to EXPECT_FLOAT_EQ which can tolerate floating-point
+// errors.
+
+// For integer geometry types, or for floating-point geometry types when you
+// know there are no floating-point errors, you can just use EXPECT_EQ.
+
+#define EXPECT_AXIS_TRANSFORM2D_EQ(a, b) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertAxisTransform2dFloatEqual, a, b)
+
+::testing::AssertionResult AssertAxisTransform2dFloatEqual(
+ const char* lhs_expr,
+ const char* rhs_expr,
+ const AxisTransform2d& lhs,
+ const AxisTransform2d& rhs);
+
+#define EXPECT_TRANSFORM_EQ(a, b) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertTransformFloatEqual, a, b)
+
+::testing::AssertionResult AssertTransformFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const Transform& lhs,
+ const Transform& rhs);
+
+#define EXPECT_TRANSFORM_NEAR(a, b, abs_error) \
+ EXPECT_PRED_FORMAT3(::gfx::AssertTransformFloatNear, a, b, abs_error)
+
+::testing::AssertionResult AssertTransformFloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const Transform& lhs,
+ const Transform& rhs,
+ float abs_error);
+
+#define EXPECT_QUATERNION_EQ(a, b) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertQuaternionFloatEqual, a, b)
+
+::testing::AssertionResult AssertQuaternionFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const Quaternion& lhs,
+ const Quaternion& rhs);
+
+#define EXPECT_QUATERNION_NEAR(a, b, abs_error) \
+ EXPECT_PRED_FORMAT3(::gfx::AssertQuaternionFloatNear, a, b, abs_error)
+
+::testing::AssertionResult AssertQuaternionFloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const Quaternion& lhs,
+ const Quaternion& rhs,
+ float abs_error);
+
+#define EXPECT_DECOMPOSED_TRANSFORM_EQ(a, b) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertDecomposedTransformFloatEqual, a, b)
+
+::testing::AssertionResult AssertDecomposedTransformFloatEqual(
+ const char* lhs_expr,
+ const char* rhs_expr,
+ const DecomposedTransform& lhs,
+ const DecomposedTransform& rhs);
+
+#define EXPECT_DECOMPOSED_TRANSFORM_NEAR(a, b, abs_error) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertDecomposedTransformFloatNear, a, b, \
+ abs_error)
+
+::testing::AssertionResult AssertDecomposedTransformFloatNear(
+ const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const DecomposedTransform& lhs,
+ const DecomposedTransform& rhs,
+ float abs_error);
+
+#define EXPECT_BOXF_EQ(a, b) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertBoxFloatEqual, a, b)
+
+::testing::AssertionResult AssertBoxFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const BoxF& lhs,
+ const BoxF& rhs);
+
+#define EXPECT_BOXF_NEAR(a, b, abs_error) \
+ EXPECT_PRED_FORMAT3(::gfx::AssertBoxFloatNear, a, b, abs_error)
+
+::testing::AssertionResult AssertBoxFloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const BoxF& lhs,
+ const BoxF& rhs,
+ float abs_error);
+
+#define EXPECT_POINTF_EQ(a, b) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertPointFloatEqual, a, b)
+
+::testing::AssertionResult AssertPointFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const PointF& lhs,
+ const PointF& rhs);
+
+#define EXPECT_POINTF_NEAR(a, b, abs_error) \
+ EXPECT_PRED_FORMAT3(::gfx::AssertPointFloatNear, a, b, abs_error)
+
+::testing::AssertionResult AssertPointFloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const PointF& lhs,
+ const PointF& rhs,
+ float abs_error);
+
+#define EXPECT_POINT3F_EQ(a, b) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertPoint3FloatEqual, a, b)
+
+::testing::AssertionResult AssertPoint3FloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const Point3F& lhs,
+ const Point3F& rhs);
+
+#define EXPECT_POINT3F_NEAR(a, b, abs_error) \
+ EXPECT_PRED_FORMAT3(::gfx::AssertPoint3FloatNear, a, b, abs_error)
+
+::testing::AssertionResult AssertPoint3FloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const Point3F& lhs,
+ const Point3F& rhs,
+ float abs_error);
+
+#define EXPECT_VECTOR2DF_EQ(a, b) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertVector2dFloatEqual, a, b)
+
+::testing::AssertionResult AssertVector2dFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const Vector2dF& lhs,
+ const Vector2dF& rhs);
+
+#define EXPECT_VECTOR2DF_NEAR(a, b, abs_error) \
+ EXPECT_PRED_FORMAT3(::gfx::AssertVector2dFloatNear, a, b, abs_error)
+
+::testing::AssertionResult AssertVector2dFloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const Vector2dF& lhs,
+ const Vector2dF& rhs,
+ float abs_error);
+
+#define EXPECT_VECTOR3DF_EQ(a, b) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertVector3dFloatEqual, a, b)
+
+::testing::AssertionResult AssertVector3dFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const Vector3dF& lhs,
+ const Vector3dF& rhs);
+
+#define EXPECT_VECTOR3DF_NEAR(a, b, abs_error) \
+ EXPECT_PRED_FORMAT3(::gfx::AssertVector3dFloatNear, a, b, abs_error)
+
+::testing::AssertionResult AssertVector3dFloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const Vector3dF& lhs,
+ const Vector3dF& rhs,
+ float abs_error);
+
+#define EXPECT_RECTF_EQ(a, b) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertRectFloatEqual, a, b)
+
+::testing::AssertionResult AssertRectFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const RectF& lhs,
+ const RectF& rhs);
+
+#define EXPECT_RECTF_NEAR(a, b, abs_error) \
+ EXPECT_PRED_FORMAT3(::gfx::AssertRectFloatNear, a, b, abs_error)
+
+::testing::AssertionResult AssertRectFloatNear(const char* lhs_expr,
+ const char* rhs_expr,
+ const char* abs_error_expr,
+ const RectF& lhs,
+ const RectF& rhs,
+ float abs_error);
+
+#define EXPECT_SKRECT_EQ(a, b) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertSkRectFloatEqual, a, b)
+
+::testing::AssertionResult AssertSkRectFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const SkRect& lhs,
+ const SkRect& rhs);
+
+#define EXPECT_SIZEF_EQ(a, b) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertSizeFloatEqual, a, b)
+
+::testing::AssertionResult AssertSizeFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const SizeF& lhs,
+ const SizeF& rhs);
+
+#define EXPECT_SKSIZE_EQ(a, b) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertSkSizeFloatEqual, a, b)
+
+::testing::AssertionResult AssertSkSizeFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const SkSize& lhs,
+ const SkSize& rhs);
+
+#define EXPECT_INSETSF_EQ(a, b) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertInsetsFloatEqual, a, b)
+
+::testing::AssertionResult AssertInsetsFloatEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ const InsetsF& lhs,
+ const InsetsF& rhs);
+
+void PrintTo(const SkRect& rect, ::std::ostream* os);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_TEST_GEOMETRY_UTIL_H_
diff --git a/ui/gfx/geometry/test/rect_test_util.cc b/ui/gfx/geometry/test/rect_test_util.cc
deleted file mode 100644
index bcc943b..0000000
--- a/ui/gfx/geometry/test/rect_test_util.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/geometry/test/rect_test_util.h"
-
-namespace gfx {
-namespace test {
-
-testing::AssertionResult RectContains(const gfx::Rect& outer_rect,
- const gfx::Rect& inner_rect) {
- if (outer_rect.Contains(inner_rect)) {
- return testing::AssertionSuccess()
- << "outer_rect (" << outer_rect.ToString()
- << ") does contain inner_rect (" << inner_rect.ToString() << ")";
- }
- return testing::AssertionFailure() << "outer_rect (" << outer_rect.ToString()
- << ") does not contain inner_rect ("
- << inner_rect.ToString() << ")";
-}
-
-} // namespace test
-} // namespace gfx
diff --git a/ui/gfx/geometry/test/rect_test_util.h b/ui/gfx/geometry/test/rect_test_util.h
deleted file mode 100644
index 91d7b2a..0000000
--- a/ui/gfx/geometry/test/rect_test_util.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_GEOMETRY_TEST_RECT_TEST_UTIL_H_
-#define UI_GFX_GEOMETRY_TEST_RECT_TEST_UTIL_H_
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace gfx {
-namespace test {
-
-testing::AssertionResult RectContains(const gfx::Rect& outer_rect,
- const gfx::Rect& inner_rect);
-
-} // namespace test
-} // namespace gfx
-
-#endif // UI_GFX_GEOMETRY_TEST_RECT_TEST_UTIL_H_
diff --git a/ui/gfx/geometry/test/size_test_util.h b/ui/gfx/geometry/test/size_test_util.h
deleted file mode 100644
index 43a6739..0000000
--- a/ui/gfx/geometry/test/size_test_util.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_GEOMETRY_TEST_SIZE_TEST_UTIL_H_
-#define UI_GFX_GEOMETRY_TEST_SIZE_TEST_UTIL_H_
-
-#define EXPECT_FLOAT_SIZE_EQ(expected, actual) \
- do { \
- EXPECT_FLOAT_EQ((expected).width(), (actual).width()); \
- EXPECT_FLOAT_EQ((expected).height(), (actual).height()); \
- } while (false)
-
-#define EXPECT_SIZE_EQ(expected, actual) \
- do { \
- EXPECT_EQ((expected).width(), (actual).width()); \
- EXPECT_EQ((expected).height(), (actual).height()); \
- } while (false)
-
-#endif // UI_GFX_GEOMETRY_TEST_SIZE_TEST_UTIL_H_
diff --git a/ui/gfx/geometry/test/transform_test_util.cc b/ui/gfx/geometry/test/transform_test_util.cc
deleted file mode 100644
index e8fa4b5..0000000
--- a/ui/gfx/geometry/test/transform_test_util.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/geometry/test/transform_test_util.h"
-
-#include "base/check.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace gfx {
-
-// NOTE: even though transform data types use double precision, we only check
-// for equality within single-precision error bounds because many transforms
-// originate from single-precision data types such as quads/rects/etc.
-
-void ExpectTransformationMatrixEq(const Transform& expected,
- const Transform& actual) {
- for (int row = 0; row < 4; ++row) {
- for (int col = 0; col < 4; ++col) {
- EXPECT_FLOAT_EQ(expected.matrix().get(row, col),
- actual.matrix().get(row, col))
- << "row: " << row << " col: " << col;
- }
- }
-}
-
-void ExpectTransformationMatrixNear(const Transform& expected,
- const Transform& actual,
- float abs_error) {
- for (int row = 0; row < 4; ++row) {
- for (int col = 0; col < 4; ++col) {
- EXPECT_NEAR(expected.matrix().get(row, col),
- actual.matrix().get(row, col), abs_error)
- << "row: " << row << " col: " << col;
- }
- }
-}
-
-Transform InvertAndCheck(const Transform& transform) {
- Transform result(Transform::kSkipInitialization);
- bool inverted_successfully = transform.GetInverse(&result);
- DCHECK(inverted_successfully);
- return result;
-}
-
-} // namespace gfx
diff --git a/ui/gfx/geometry/test/transform_test_util.h b/ui/gfx/geometry/test/transform_test_util.h
deleted file mode 100644
index b9dbc90..0000000
--- a/ui/gfx/geometry/test/transform_test_util.h
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_GEOMETRY_TEST_TRANSFORM_TEST_UTIL_H_
-#define UI_GFX_GEOMETRY_TEST_TRANSFORM_TEST_UTIL_H_
-
-#include "ui/gfx/geometry/transform.h"
-
-namespace gfx {
-
-// This is a function rather than a macro because when this is included as a
-// macro in bulk, it causes a significant slow-down in compilation time. This
-// problem exists with both gcc and clang, and bugs have been filed at
-// http://llvm.org/bugs/show_bug.cgi?id=13651
-// and http://gcc.gnu.org/bugzilla/show_bug.cgi?id=54337
-void ExpectTransformationMatrixEq(const Transform& expected,
- const Transform& actual);
-
-void ExpectTransformationMatrixNear(const Transform& expected,
- const Transform& actual,
- float abs_error);
-
-// Should be used in test code only, for convenience. Production code should use
-// the gfx::Transform::GetInverse() API.
-Transform InvertAndCheck(const Transform& transform);
-
-} // namespace gfx
-
-#endif // UI_GFX_GEOMETRY_TEST_TRANSFORM_TEST_UTIL_H_
diff --git a/ui/gfx/geometry/transform.cc b/ui/gfx/geometry/transform.cc
index eee5af7..2ffb937 100644
--- a/ui/gfx/geometry/transform.cc
+++ b/ui/gfx/geometry/transform.cc
@@ -1,19 +1,26 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/transform.h"
+#include <ostream>
+
#include "base/check_op.h"
+#include "base/notreached.h"
#include "base/strings/stringprintf.h"
#include "ui/gfx/geometry/angle_conversions.h"
+#include "ui/gfx/geometry/axis_transform2d.h"
#include "ui/gfx/geometry/box_f.h"
+#include "ui/gfx/geometry/clamp_float_geometry.h"
+#include "ui/gfx/geometry/decomposed_transform.h"
+#include "ui/gfx/geometry/double4.h"
#include "ui/gfx/geometry/point3_f.h"
#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/quad_f.h"
#include "ui/gfx/geometry/quaternion.h"
#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/rrect_f.h"
-#include "ui/gfx/geometry/skia_conversions.h"
+#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/transform_util.h"
#include "ui/gfx/geometry/vector3d_f.h"
@@ -21,217 +28,353 @@
namespace {
-const SkScalar kEpsilon = std::numeric_limits<float>::epsilon();
+const double kEpsilon = std::numeric_limits<float>::epsilon();
-SkScalar TanDegrees(double degrees) {
- return SkDoubleToScalar(std::tan(gfx::DegToRad(degrees)));
+double TanDegrees(double degrees) {
+ return std::tan(DegToRad(degrees));
}
-inline bool ApproximatelyZero(SkScalar x, SkScalar tolerance) {
+struct SinCos {
+ double sin;
+ double cos;
+ bool IsZeroAngle() const { return sin == 0 && cos == 1; }
+};
+
+SinCos SinCosDegrees(double degrees) {
+ double n90degrees = degrees / 90.0;
+ int n = static_cast<int>(n90degrees);
+ if (n == n90degrees) {
+ n %= 4;
+ if (n < 0)
+ n += 4;
+ constexpr SinCos kSinCosN90[] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
+ return kSinCosN90[n];
+ }
+ // fmod is to reduce errors of DegToRad() with large |degrees|.
+ double rad = DegToRad(std::fmod(degrees, 360.0));
+ return SinCos{std::sin(rad), std::cos(rad)};
+}
+
+inline bool ApproximatelyZero(double x, double tolerance) {
return std::abs(x) <= tolerance;
}
-inline bool ApproximatelyOne(SkScalar x, SkScalar tolerance) {
+inline bool ApproximatelyOne(double x, double tolerance) {
return std::abs(x - 1) <= tolerance;
}
+Matrix44 AxisTransform2dToMatrix44(const AxisTransform2d& axis_2d) {
+ return Matrix44(axis_2d.scale().x(), 0, 0, 0, // col 0
+ 0, axis_2d.scale().y(), 0, 0, // col 1
+ 0, 0, 1, 0, // col 2
+ axis_2d.translation().x(), axis_2d.translation().y(), 0, 1);
+}
+
+template <typename T>
+void AxisTransform2dToColMajor(const AxisTransform2d& axis_2d, T a[16]) {
+ a[0] = axis_2d.scale().x();
+ a[5] = axis_2d.scale().y();
+ a[12] = axis_2d.translation().x();
+ a[13] = axis_2d.translation().y();
+ a[1] = a[2] = a[3] = a[4] = a[6] = a[7] = a[8] = a[9] = a[11] = a[14] = 0;
+ a[10] = a[15] = 1;
+}
+
} // namespace
-Transform::Transform(SkScalar col1row1,
- SkScalar col2row1,
- SkScalar col3row1,
- SkScalar col4row1,
- SkScalar col1row2,
- SkScalar col2row2,
- SkScalar col3row2,
- SkScalar col4row2,
- SkScalar col1row3,
- SkScalar col2row3,
- SkScalar col3row3,
- SkScalar col4row3,
- SkScalar col1row4,
- SkScalar col2row4,
- SkScalar col3row4,
- SkScalar col4row4)
- : matrix_(skia::Matrix44::kUninitialized_Constructor) {
- matrix_.set4x4(col1row1, col1row2, col1row3, col1row4, col2row1, col2row2,
- col2row3, col2row4, col3row1, col3row2, col3row3, col3row4,
- col4row1, col4row2, col4row3, col4row4);
-}
-
-Transform::Transform(SkScalar col1row1,
- SkScalar col2row1,
- SkScalar col1row2,
- SkScalar col2row2,
- SkScalar x_translation,
- SkScalar y_translation)
- : matrix_(skia::Matrix44::kUninitialized_Constructor) {
- matrix_.set4x4(col1row1, col1row2, 0, 0, col2row1, col2row2, 0, 0, 0, 0, 1, 0,
- x_translation, y_translation, 0, 1);
-}
-
+// clang-format off
Transform::Transform(const Quaternion& q)
- : matrix_(skia::Matrix44::kUninitialized_Constructor) {
- double x = q.x();
- double y = q.y();
- double z = q.z();
- double w = q.w();
+ : Transform(
+ // Col 0.
+ 1.0 - 2.0 * (q.y() * q.y() + q.z() * q.z()),
+ 2.0 * (q.x() * q.y() + q.z() * q.w()),
+ 2.0 * (q.x() * q.z() - q.y() * q.w()),
+ 0,
+ // Col 1.
+ 2.0 * (q.x() * q.y() - q.z() * q.w()),
+ 1.0 - 2.0 * (q.x() * q.x() + q.z() * q.z()),
+ 2.0 * (q.y() * q.z() + q.x() * q.w()),
+ 0,
+ // Col 2.
+ 2.0 * (q.x() * q.z() + q.y() * q.w()),
+ 2.0 * (q.y() * q.z() - q.x() * q.w()),
+ 1.0 - 2.0 * (q.x() * q.x() + q.y() * q.y()),
+ 0,
+ // Col 3.
+ 0, 0, 0, 1) {}
+// clang-format on
- // Implicitly calls matrix.setIdentity()
- matrix_.set3x3(SkDoubleToScalar(1.0 - 2.0 * (y * y + z * z)),
- SkDoubleToScalar(2.0 * (x * y + z * w)),
- SkDoubleToScalar(2.0 * (x * z - y * w)),
- SkDoubleToScalar(2.0 * (x * y - z * w)),
- SkDoubleToScalar(1.0 - 2.0 * (x * x + z * z)),
- SkDoubleToScalar(2.0 * (y * z + x * w)),
- SkDoubleToScalar(2.0 * (x * z + y * w)),
- SkDoubleToScalar(2.0 * (y * z - x * w)),
- SkDoubleToScalar(1.0 - 2.0 * (x * x + y * y)));
+Matrix44 Transform::GetFullMatrix() const {
+ if (LIKELY(!full_matrix_))
+ return AxisTransform2dToMatrix44(axis_2d_);
+ return matrix_;
+}
+
+Matrix44& Transform::EnsureFullMatrix() {
+ if (LIKELY(!full_matrix_)) {
+ full_matrix_ = true;
+ matrix_ = AxisTransform2dToMatrix44(axis_2d_);
+ }
+ return matrix_;
+}
+
+// static
+Transform Transform::ColMajor(const double a[16]) {
+ return Transform(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9],
+ a[10], a[11], a[12], a[13], a[14], a[15]);
+}
+
+// static
+Transform Transform::ColMajorF(const float a[16]) {
+ if (AllTrue(Float4{a[1], a[2], a[3], a[4]} == Float4{0, 0, 0, 0} &
+ Float4{a[6], a[7], a[8], a[9]} == Float4{0, 0, 0, 0} &
+ Float4{a[10], a[11], a[14], a[15]} == Float4{1, 0, 0, 1})) {
+ return Transform(a[0], a[5], a[12], a[13]);
+ }
+ return Transform(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9],
+ a[10], a[11], a[12], a[13], a[14], a[15]);
+}
+
+void Transform::GetColMajor(double a[16]) const {
+ if (LIKELY(!full_matrix_)) {
+ AxisTransform2dToColMajor(axis_2d_, a);
+ } else {
+ matrix_.GetColMajor(a);
+ }
+}
+
+void Transform::GetColMajorF(float a[16]) const {
+ if (LIKELY(!full_matrix_)) {
+ AxisTransform2dToColMajor(axis_2d_, a);
+ } else {
+ matrix_.GetColMajorF(a);
+ }
}
void Transform::RotateAboutXAxis(double degrees) {
- double radians = gfx::DegToRad(degrees);
- SkScalar cosTheta = SkDoubleToScalar(std::cos(radians));
- SkScalar sinTheta = SkDoubleToScalar(std::sin(radians));
- if (matrix_.isIdentity()) {
- matrix_.set3x3(1, 0, 0, 0, cosTheta, sinTheta, 0, -sinTheta, cosTheta);
- } else {
- skia::Matrix44 rot(skia::Matrix44::kUninitialized_Constructor);
- rot.set3x3(1, 0, 0, 0, cosTheta, sinTheta, 0, -sinTheta, cosTheta);
- matrix_.preConcat(rot);
- }
+ SinCos sin_cos = SinCosDegrees(degrees);
+ if (sin_cos.IsZeroAngle())
+ return;
+ EnsureFullMatrix().RotateAboutXAxisSinCos(sin_cos.sin, sin_cos.cos);
}
void Transform::RotateAboutYAxis(double degrees) {
- double radians = gfx::DegToRad(degrees);
- SkScalar cosTheta = SkDoubleToScalar(std::cos(radians));
- SkScalar sinTheta = SkDoubleToScalar(std::sin(radians));
- if (matrix_.isIdentity()) {
- // Note carefully the placement of the -sinTheta for rotation about
- // y-axis is different than rotation about x-axis or z-axis.
- matrix_.set3x3(cosTheta, 0, -sinTheta, 0, 1, 0, sinTheta, 0, cosTheta);
- } else {
- skia::Matrix44 rot(skia::Matrix44::kUninitialized_Constructor);
- rot.set3x3(cosTheta, 0, -sinTheta, 0, 1, 0, sinTheta, 0, cosTheta);
- matrix_.preConcat(rot);
- }
+ SinCos sin_cos = SinCosDegrees(degrees);
+ if (sin_cos.IsZeroAngle())
+ return;
+ EnsureFullMatrix().RotateAboutYAxisSinCos(sin_cos.sin, sin_cos.cos);
}
void Transform::RotateAboutZAxis(double degrees) {
- double radians = gfx::DegToRad(degrees);
- SkScalar cosTheta = SkDoubleToScalar(std::cos(radians));
- SkScalar sinTheta = SkDoubleToScalar(std::sin(radians));
- if (matrix_.isIdentity()) {
- matrix_.set3x3(cosTheta, sinTheta, 0, -sinTheta, cosTheta, 0, 0, 0, 1);
- } else {
- skia::Matrix44 rot(skia::Matrix44::kUninitialized_Constructor);
- rot.set3x3(cosTheta, sinTheta, 0, -sinTheta, cosTheta, 0, 0, 0, 1);
- matrix_.preConcat(rot);
+ SinCos sin_cos = SinCosDegrees(degrees);
+ if (sin_cos.IsZeroAngle())
+ return;
+ EnsureFullMatrix().RotateAboutZAxisSinCos(sin_cos.sin, sin_cos.cos);
+}
+
+void Transform::RotateAbout(double x, double y, double z, double degrees) {
+ SinCos sin_cos = SinCosDegrees(degrees);
+ if (sin_cos.IsZeroAngle())
+ return;
+
+ double square_length = x * x + y * y + z * z;
+ if (square_length == 0)
+ return;
+ if (square_length != 1) {
+ double scale = 1.0 / sqrt(square_length);
+ x *= scale;
+ y *= scale;
+ z *= scale;
}
+ EnsureFullMatrix().RotateUnitSinCos(x, y, z, sin_cos.sin, sin_cos.cos);
}
void Transform::RotateAbout(const Vector3dF& axis, double degrees) {
- if (matrix_.isIdentity()) {
- matrix_.setRotateDegreesAbout(axis.x(), axis.y(), axis.z(),
- SkDoubleToScalar(degrees));
- } else {
- skia::Matrix44 rot(skia::Matrix44::kUninitialized_Constructor);
- rot.setRotateDegreesAbout(axis.x(), axis.y(), axis.z(),
- SkDoubleToScalar(degrees));
- matrix_.preConcat(rot);
- }
+ RotateAbout(axis.x(), axis.y(), axis.z(), degrees);
}
-void Transform::Scale(SkScalar x, SkScalar y) {
- matrix_.preScale(x, y, 1);
+double Transform::Determinant() const {
+ return LIKELY(!full_matrix_) ? axis_2d_.Determinant() : matrix_.Determinant();
}
-void Transform::PostScale(SkScalar x, SkScalar y) {
- matrix_.postScale(x, y, 1);
+void Transform::Scale(float x, float y) {
+ if (LIKELY(!full_matrix_))
+ axis_2d_.PreScale(Vector2dF(x, y));
+ else
+ matrix_.PreScale(x, y);
}
-void Transform::Scale3d(SkScalar x, SkScalar y, SkScalar z) {
- matrix_.preScale(x, y, z);
+void Transform::PostScale(float x, float y) {
+ if (LIKELY(!full_matrix_))
+ axis_2d_.PostScale(Vector2dF(x, y));
+ else
+ matrix_.PostScale(x, y);
+}
+
+void Transform::Scale3d(float x, float y, float z) {
+ if (z == 1)
+ Scale(x, y);
+ else
+ EnsureFullMatrix().PreScale3d(x, y, z);
+}
+
+void Transform::PostScale3d(float x, float y, float z) {
+ if (z == 1)
+ PostScale(x, y);
+ else
+ EnsureFullMatrix().PostScale3d(x, y, z);
}
void Transform::Translate(const Vector2dF& offset) {
Translate(offset.x(), offset.y());
}
-void Transform::Translate(SkScalar x, SkScalar y) {
- matrix_.preTranslate(x, y, 0);
+void Transform::Translate(float x, float y) {
+ if (LIKELY(!full_matrix_))
+ axis_2d_.PreTranslate(Vector2dF(x, y));
+ else
+ matrix_.PreTranslate(x, y);
}
void Transform::PostTranslate(const Vector2dF& offset) {
PostTranslate(offset.x(), offset.y());
}
-void Transform::PostTranslate(SkScalar x, SkScalar y) {
- matrix_.postTranslate(x, y, 0);
+void Transform::PostTranslate(float x, float y) {
+ if (LIKELY(!full_matrix_))
+ axis_2d_.PostTranslate(Vector2dF(x, y));
+ else
+ matrix_.PostTranslate(x, y);
+}
+
+void Transform::PostTranslate3d(const Vector3dF& offset) {
+ PostTranslate3d(offset.x(), offset.y(), offset.z());
+}
+
+void Transform::PostTranslate3d(float x, float y, float z) {
+ if (z == 0)
+ PostTranslate(x, y);
+ else
+ EnsureFullMatrix().PostTranslate3d(x, y, z);
}
void Transform::Translate3d(const Vector3dF& offset) {
Translate3d(offset.x(), offset.y(), offset.z());
}
-void Transform::Translate3d(SkScalar x, SkScalar y, SkScalar z) {
- matrix_.preTranslate(x, y, z);
+void Transform::Translate3d(float x, float y, float z) {
+ if (z == 0)
+ Translate(x, y);
+ else
+ EnsureFullMatrix().PreTranslate3d(x, y, z);
}
-void Transform::Skew(double angle_x, double angle_y) {
- if (matrix_.isIdentity()) {
- matrix_.set(0, 1, TanDegrees(angle_x));
- matrix_.set(1, 0, TanDegrees(angle_y));
- } else {
- skia::Matrix44 skew(skia::Matrix44::kIdentity_Constructor);
- skew.set(0, 1, TanDegrees(angle_x));
- skew.set(1, 0, TanDegrees(angle_y));
- matrix_.preConcat(skew);
- }
+void Transform::Skew(double degrees_x, double degrees_y) {
+ if (!degrees_x && !degrees_y)
+ return;
+ EnsureFullMatrix().Skew(TanDegrees(degrees_x), TanDegrees(degrees_y));
}
-void Transform::ApplyPerspectiveDepth(SkScalar depth) {
+void Transform::ApplyPerspectiveDepth(double depth) {
if (depth == 0)
return;
- if (matrix_.isIdentity()) {
- matrix_.set(3, 2, -SK_Scalar1 / depth);
+
+ EnsureFullMatrix().ApplyPerspectiveDepth(depth);
+}
+
+void Transform::PreConcat(const Transform& transform) {
+ if (LIKELY(!transform.full_matrix_)) {
+ PreConcat(transform.axis_2d_);
+ } else if (LIKELY(!full_matrix_)) {
+ AxisTransform2d self = axis_2d_;
+ *this = transform;
+ PostConcat(self);
} else {
- skia::Matrix44 m(skia::Matrix44::kIdentity_Constructor);
- m.set(3, 2, -SK_Scalar1 / depth);
- matrix_.preConcat(m);
+ matrix_.PreConcat(transform.matrix_);
}
}
-void Transform::PreconcatTransform(const Transform& transform) {
- matrix_.preConcat(transform.matrix_);
+void Transform::PostConcat(const Transform& transform) {
+ if (LIKELY(!transform.full_matrix_)) {
+ PostConcat(transform.axis_2d_);
+ } else if (LIKELY(!full_matrix_)) {
+ AxisTransform2d self = axis_2d_;
+ *this = transform;
+ PreConcat(self);
+ } else {
+ matrix_.PostConcat(transform.matrix_);
+ }
}
-void Transform::ConcatTransform(const Transform& transform) {
- matrix_.postConcat(transform.matrix_);
+Transform Transform::operator*(const Transform& transform) const {
+ if (LIKELY(!transform.full_matrix_)) {
+ Transform result = *this;
+ result.PreConcat(transform.axis_2d_);
+ return result;
+ }
+ if (LIKELY(!full_matrix_)) {
+ Transform result = transform;
+ result.PostConcat(axis_2d_);
+ return result;
+ }
+ Transform result(Matrix44::kUninitialized);
+ result.matrix_.SetConcat(matrix_, transform.matrix_);
+ return result;
}
-bool Transform::IsApproximatelyIdentityOrTranslation(SkScalar tolerance) const {
+void Transform::PreConcat(const AxisTransform2d& transform) {
+ Translate(transform.translation());
+ Scale(transform.scale().x(), transform.scale().y());
+}
+
+void Transform::PostConcat(const AxisTransform2d& transform) {
+ PostScale(transform.scale().x(), transform.scale().y());
+ PostTranslate(transform.translation());
+}
+
+bool Transform::IsApproximatelyIdentityOrTranslation(double tolerance) const {
DCHECK_GE(tolerance, 0);
- return ApproximatelyOne(matrix_.get(0, 0), tolerance) &&
- ApproximatelyZero(matrix_.get(1, 0), tolerance) &&
- ApproximatelyZero(matrix_.get(2, 0), tolerance) &&
- matrix_.get(3, 0) == 0 &&
- ApproximatelyZero(matrix_.get(0, 1), tolerance) &&
- ApproximatelyOne(matrix_.get(1, 1), tolerance) &&
- ApproximatelyZero(matrix_.get(2, 1), tolerance) &&
- matrix_.get(3, 1) == 0 &&
- ApproximatelyZero(matrix_.get(0, 2), tolerance) &&
- ApproximatelyZero(matrix_.get(1, 2), tolerance) &&
- ApproximatelyOne(matrix_.get(2, 2), tolerance) &&
- matrix_.get(3, 2) == 0 && matrix_.get(3, 3) == 1;
+ if (LIKELY(!full_matrix_)) {
+ return ApproximatelyOne(axis_2d_.scale().x(), tolerance) &&
+ ApproximatelyOne(axis_2d_.scale().y(), tolerance);
+ }
+
+ if (!ApproximatelyOne(matrix_.rc(0, 0), tolerance) ||
+ !ApproximatelyZero(matrix_.rc(1, 0), tolerance) ||
+ !ApproximatelyZero(matrix_.rc(2, 0), tolerance) ||
+ !ApproximatelyZero(matrix_.rc(0, 1), tolerance) ||
+ !ApproximatelyOne(matrix_.rc(1, 1), tolerance) ||
+ !ApproximatelyZero(matrix_.rc(2, 1), tolerance) ||
+ !ApproximatelyZero(matrix_.rc(0, 2), tolerance) ||
+ !ApproximatelyZero(matrix_.rc(1, 2), tolerance) ||
+ !ApproximatelyOne(matrix_.rc(2, 2), tolerance)) {
+ return false;
+ }
+
+ // Check perspective components more strictly by using the smaller of float
+ // epsilon and |tolerance|.
+ const double perspective_tolerance = std::min(kEpsilon, tolerance);
+ return ApproximatelyZero(matrix_.rc(3, 0), perspective_tolerance) &&
+ ApproximatelyZero(matrix_.rc(3, 1), perspective_tolerance) &&
+ ApproximatelyZero(matrix_.rc(3, 2), perspective_tolerance) &&
+ ApproximatelyOne(matrix_.rc(3, 3), perspective_tolerance);
}
bool Transform::IsApproximatelyIdentityOrIntegerTranslation(
- SkScalar tolerance) const {
+ double tolerance) const {
if (!IsApproximatelyIdentityOrTranslation(tolerance))
return false;
- for (float t : {matrix_.get(0, 3), matrix_.get(1, 3), matrix_.get(2, 3)}) {
+ if (LIKELY(!full_matrix_)) {
+ for (float t : {axis_2d_.translation().x(), axis_2d_.translation().y()}) {
+ if (!base::IsValueInRangeForNumericType<int>(t) ||
+ std::abs(std::round(t) - t) > tolerance)
+ return false;
+ }
+ return true;
+ }
+
+ for (double t : {matrix_.rc(0, 3), matrix_.rc(1, 3), matrix_.rc(2, 3)}) {
if (!base::IsValueInRangeForNumericType<int>(t) ||
std::abs(std::round(t) - t) > tolerance)
return false;
@@ -239,23 +382,57 @@
return true;
}
+bool Transform::Is2dProportionalUpscaleAndOr2dTranslation() const {
+ if (LIKELY(!full_matrix_)) {
+ return axis_2d_.scale().x() >= 1 &&
+ axis_2d_.scale().x() == axis_2d_.scale().y();
+ }
+
+ return matrix_.IsScaleOrTranslation() &&
+ // Check proportional upscale.
+ matrix_.rc(0, 0) >= 1 && matrix_.rc(1, 1) == matrix_.rc(0, 0) &&
+ // Check no scale/translation in z axis.
+ matrix_.rc(2, 2) == 1 && matrix_.rc(2, 3) == 0;
+}
+
bool Transform::IsIdentityOrIntegerTranslation() const {
if (!IsIdentityOrTranslation())
return false;
- for (float t : {matrix_.get(0, 3), matrix_.get(1, 3), matrix_.get(2, 3)}) {
+ if (LIKELY(!full_matrix_)) {
+ for (float t : {axis_2d_.translation().x(), axis_2d_.translation().y()}) {
+ if (!base::IsValueInRangeForNumericType<int>(t) ||
+ static_cast<int>(t) != t) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ for (double t : {matrix_.rc(0, 3), matrix_.rc(1, 3), matrix_.rc(2, 3)}) {
if (!base::IsValueInRangeForNumericType<int>(t) || static_cast<int>(t) != t)
return false;
}
return true;
}
+bool Transform::IsIdentityOrInteger2dTranslation() const {
+ return IsIdentityOrIntegerTranslation() && rc(2, 3) == 0;
+}
+
+bool Transform::Creates3d() const {
+ if (LIKELY(!full_matrix_))
+ return false;
+ return matrix_.rc(2, 0) != 0 || matrix_.rc(2, 1) != 0 ||
+ matrix_.rc(2, 3) != 0;
+}
+
bool Transform::IsBackFaceVisible() const {
- // Compute whether a layer with a forward-facing normal of (0, 0, 1, 0)
- // would have its back face visible after applying the transform.
- if (matrix_.isIdentity())
+ if (LIKELY(!full_matrix_))
return false;
+ // Compute whether a layer with a forward-facing normal of (0, 0, 1, 0)
+ // would have its back face visible after applying the transform.
// This is done by transforming the normal and seeing if the resulting z
// value is positive or negative. However, note that transforming a normal
// actually requires using the inverse-transpose of the original transform.
@@ -270,7 +447,7 @@
// http://en.wikipedia.org/wiki/Invertible_matrix#Analytic_solution
//
- double determinant = matrix_.determinant();
+ double determinant = matrix_.Determinant();
// If matrix was not invertible, then just assume back face is not visible.
if (determinant == 0)
@@ -278,22 +455,22 @@
// Compute the cofactor of the 3rd row, 3rd column.
double cofactor_part_1 =
- matrix_.get(0, 0) * matrix_.get(1, 1) * matrix_.get(3, 3);
+ matrix_.rc(0, 0) * matrix_.rc(1, 1) * matrix_.rc(3, 3);
double cofactor_part_2 =
- matrix_.get(0, 1) * matrix_.get(1, 3) * matrix_.get(3, 0);
+ matrix_.rc(0, 1) * matrix_.rc(1, 3) * matrix_.rc(3, 0);
double cofactor_part_3 =
- matrix_.get(0, 3) * matrix_.get(1, 0) * matrix_.get(3, 1);
+ matrix_.rc(0, 3) * matrix_.rc(1, 0) * matrix_.rc(3, 1);
double cofactor_part_4 =
- matrix_.get(0, 0) * matrix_.get(1, 3) * matrix_.get(3, 1);
+ matrix_.rc(0, 0) * matrix_.rc(1, 3) * matrix_.rc(3, 1);
double cofactor_part_5 =
- matrix_.get(0, 1) * matrix_.get(1, 0) * matrix_.get(3, 3);
+ matrix_.rc(0, 1) * matrix_.rc(1, 0) * matrix_.rc(3, 3);
double cofactor_part_6 =
- matrix_.get(0, 3) * matrix_.get(1, 1) * matrix_.get(3, 0);
+ matrix_.rc(0, 3) * matrix_.rc(1, 1) * matrix_.rc(3, 0);
double cofactor33 = cofactor_part_1 + cofactor_part_2 + cofactor_part_3 -
cofactor_part_4 - cofactor_part_5 - cofactor_part_6;
@@ -305,17 +482,46 @@
}
bool Transform::GetInverse(Transform* transform) const {
- if (!matrix_.invert(&transform->matrix_)) {
- // Initialize the return value to identity if this matrix turned
- // out to be un-invertible.
- transform->MakeIdentity();
+ if (LIKELY(!full_matrix_)) {
+ transform->full_matrix_ = false;
+ if (axis_2d_.IsInvertible()) {
+ transform->axis_2d_ = axis_2d_;
+ transform->axis_2d_.Invert();
+ return true;
+ }
+ transform->axis_2d_ = AxisTransform2d();
return false;
}
- return true;
+ if (matrix_.GetInverse(transform->matrix_)) {
+ transform->full_matrix_ = true;
+ return true;
+ }
+
+ // Initialize the return value to identity if this matrix turned
+ // out to be un-invertible.
+ transform->MakeIdentity();
+ return false;
+}
+
+Transform Transform::GetCheckedInverse() const {
+ Transform inverse;
+ if (!GetInverse(&inverse))
+ NOTREACHED() << ToString() << " is not invertible";
+ return inverse;
+}
+
+Transform Transform::InverseOrIdentity() const {
+ Transform inverse;
+ bool invertible = GetInverse(&inverse);
+ DCHECK(invertible || inverse.IsIdentity());
+ return inverse;
}
bool Transform::Preserves2dAxisAlignment() const {
+ if (LIKELY(!full_matrix_))
+ return true;
+
// Check whether an axis aligned 2-dimensional rect would remain axis-aligned
// after being transformed by this matrix (and implicitly projected by
// dropping any non-zero z-values).
@@ -334,30 +540,29 @@
// values: The current implementation conservatively assumes that axis
// alignment is not preserved.
- bool has_x_or_y_perspective =
- matrix_.get(3, 0) != 0 || matrix_.get(3, 1) != 0;
+ bool has_x_or_y_perspective = matrix_.rc(3, 0) != 0 || matrix_.rc(3, 1) != 0;
int num_non_zero_in_row_0 = 0;
int num_non_zero_in_row_1 = 0;
int num_non_zero_in_col_0 = 0;
int num_non_zero_in_col_1 = 0;
- if (std::abs(matrix_.get(0, 0)) > kEpsilon) {
+ if (std::abs(matrix_.rc(0, 0)) > kEpsilon) {
num_non_zero_in_row_0++;
num_non_zero_in_col_0++;
}
- if (std::abs(matrix_.get(0, 1)) > kEpsilon) {
+ if (std::abs(matrix_.rc(0, 1)) > kEpsilon) {
num_non_zero_in_row_0++;
num_non_zero_in_col_1++;
}
- if (std::abs(matrix_.get(1, 0)) > kEpsilon) {
+ if (std::abs(matrix_.rc(1, 0)) > kEpsilon) {
num_non_zero_in_row_1++;
num_non_zero_in_col_0++;
}
- if (std::abs(matrix_.get(1, 1)) > kEpsilon) {
+ if (std::abs(matrix_.rc(1, 1)) > kEpsilon) {
num_non_zero_in_row_1++;
num_non_zero_in_col_1++;
}
@@ -368,6 +573,9 @@
}
bool Transform::NonDegeneratePreserves2dAxisAlignment() const {
+ if (LIKELY(!full_matrix_))
+ return axis_2d_.scale().x() > kEpsilon && axis_2d_.scale().y() > kEpsilon;
+
// See comments above for Preserves2dAxisAlignment.
// This function differs from it by requiring:
@@ -375,132 +583,210 @@
// the upper left 2x2 submatrix, and
// (2) that the w perspective value is positive.
- bool has_x_or_y_perspective =
- matrix_.get(3, 0) != 0 || matrix_.get(3, 1) != 0;
- bool positive_w_perspective = matrix_.get(3, 3) > kEpsilon;
+ bool has_x_or_y_perspective = matrix_.rc(3, 0) != 0 || matrix_.rc(3, 1) != 0;
+ bool positive_w_perspective = matrix_.rc(3, 3) > kEpsilon;
- bool have_0_0 = std::abs(matrix_.get(0, 0)) > kEpsilon;
- bool have_0_1 = std::abs(matrix_.get(0, 1)) > kEpsilon;
- bool have_1_0 = std::abs(matrix_.get(1, 0)) > kEpsilon;
- bool have_1_1 = std::abs(matrix_.get(1, 1)) > kEpsilon;
+ bool have_0_0 = std::abs(matrix_.rc(0, 0)) > kEpsilon;
+ bool have_0_1 = std::abs(matrix_.rc(0, 1)) > kEpsilon;
+ bool have_1_0 = std::abs(matrix_.rc(1, 0)) > kEpsilon;
+ bool have_1_1 = std::abs(matrix_.rc(1, 1)) > kEpsilon;
return have_0_0 == have_1_1 && have_0_1 == have_1_0 && have_0_0 != have_0_1 &&
!has_x_or_y_perspective && positive_w_perspective;
}
void Transform::Transpose() {
- matrix_.transpose();
+ if (!IsScale2d())
+ EnsureFullMatrix().Transpose();
}
-void Transform::FlattenTo2d() {
- float tmp[16];
- matrix_.asColMajorf(tmp);
- tmp[2] = 0.0;
- tmp[6] = 0.0;
- tmp[8] = 0.0;
- tmp[9] = 0.0;
- tmp[10] = 1.0;
- tmp[11] = 0.0;
- tmp[14] = 0.0;
- matrix_.setColMajorf(tmp);
+void Transform::ApplyTransformOrigin(float x, float y, float z) {
+ PostTranslate3d(x, y, z);
+ Translate3d(-x, -y, -z);
+}
+
+void Transform::Zoom(float zoom_factor) {
+ if (LIKELY(!full_matrix_)) {
+ axis_2d_.Zoom(zoom_factor);
+ } else {
+ matrix_.Zoom(zoom_factor);
+ }
+}
+
+void Transform::Flatten() {
+ if (UNLIKELY(full_matrix_))
+ matrix_.Flatten();
+ DCHECK(IsFlat());
}
bool Transform::IsFlat() const {
- return matrix_.get(2, 0) == 0.0 && matrix_.get(2, 1) == 0.0 &&
- matrix_.get(0, 2) == 0.0 && matrix_.get(1, 2) == 0.0 &&
- matrix_.get(2, 2) == 1.0 && matrix_.get(3, 2) == 0.0 &&
- matrix_.get(2, 3) == 0.0;
+ return LIKELY(!full_matrix_) || matrix_.IsFlat();
+}
+
+bool Transform::Is2dTransform() const {
+ return LIKELY(!full_matrix_) || matrix_.Is2dTransform();
}
Vector2dF Transform::To2dTranslation() const {
- return gfx::Vector2dF(SkScalarToFloat(matrix_.get(0, 3)),
- SkScalarToFloat(matrix_.get(1, 3)));
+ if (LIKELY(!full_matrix_)) {
+ return Vector2dF(ClampFloatGeometry(axis_2d_.translation().x()),
+ ClampFloatGeometry(axis_2d_.translation().y()));
+ }
+ return Vector2dF(ClampFloatGeometry(matrix_.rc(0, 3)),
+ ClampFloatGeometry(matrix_.rc(1, 3)));
}
-void Transform::TransformPoint(Point* point) const {
- DCHECK(point);
- TransformPointInternal(matrix_, point);
+Vector3dF Transform::To3dTranslation() const {
+ if (LIKELY(!full_matrix_)) {
+ return Vector3dF(ClampFloatGeometry(axis_2d_.translation().x()),
+ ClampFloatGeometry(axis_2d_.translation().y()), 0);
+ }
+ return Vector3dF(ClampFloatGeometry(matrix_.rc(0, 3)),
+ ClampFloatGeometry(matrix_.rc(1, 3)),
+ ClampFloatGeometry(matrix_.rc(2, 3)));
}
-void Transform::TransformPoint(PointF* point) const {
- DCHECK(point);
- TransformPointInternal(matrix_, point);
+Vector2dF Transform::To2dScale() const {
+ if (LIKELY(!full_matrix_)) {
+ return Vector2dF(ClampFloatGeometry(axis_2d_.scale().x()),
+ ClampFloatGeometry(axis_2d_.scale().y()));
+ }
+ return Vector2dF(ClampFloatGeometry(matrix_.rc(0, 0)),
+ ClampFloatGeometry(matrix_.rc(1, 1)));
}
-void Transform::TransformPoint(Point3F* point) const {
- DCHECK(point);
- TransformPointInternal(matrix_, point);
+Point Transform::MapPoint(const Point& point) const {
+ return gfx::ToRoundedPoint(MapPoint(gfx::PointF(point)));
}
-void Transform::TransformVector(Vector3dF* vector) const {
+PointF Transform::MapPoint(const PointF& point) const {
+ return LIKELY(!full_matrix_) ? axis_2d_.MapPoint(point)
+ : MapPointInternal(matrix_, point);
+}
+
+Point3F Transform::MapPoint(const Point3F& point) const {
+ if (LIKELY(!full_matrix_)) {
+ PointF result = axis_2d_.MapPoint(point.AsPointF());
+ return Point3F(result.x(), result.y(), ClampFloatGeometry(point.z()));
+ }
+ return MapPointInternal(matrix_, point);
+}
+
+Vector3dF Transform::MapVector(const Vector3dF& vector) const {
+ if (LIKELY(!full_matrix_)) {
+ return Vector3dF(ClampFloatGeometry(vector.x() * axis_2d_.scale().x()),
+ ClampFloatGeometry(vector.y() * axis_2d_.scale().y()),
+ ClampFloatGeometry(vector.z()));
+ }
+ double p[4] = {vector.x(), vector.y(), vector.z(), 0};
+ matrix_.MapVector4(p);
+ return Vector3dF(ClampFloatGeometry(p[0]), ClampFloatGeometry(p[1]),
+ ClampFloatGeometry(p[2]));
+}
+
+void Transform::TransformVector4(float vector[4]) const {
DCHECK(vector);
- TransformVectorInternal(matrix_, vector);
+ if (LIKELY(!full_matrix_)) {
+ vector[0] = vector[0] * axis_2d_.scale().x() +
+ vector[3] * axis_2d_.translation().x();
+ vector[1] = vector[1] * axis_2d_.scale().y() +
+ vector[3] * axis_2d_.translation().y();
+ for (int i = 0; i < 4; i++)
+ vector[i] = ClampFloatGeometry(vector[i]);
+ } else {
+ double v[4] = {vector[0], vector[1], vector[2], vector[3]};
+ matrix_.MapVector4(v);
+ for (int i = 0; i < 4; i++)
+ vector[i] = ClampFloatGeometry(v[i]);
+ }
}
-bool Transform::TransformPointReverse(Point* point) const {
- DCHECK(point);
-
- // TODO(sad): Try to avoid trying to invert the matrix.
- skia::Matrix44 inverse(skia::Matrix44::kUninitialized_Constructor);
- if (!matrix_.invert(&inverse))
- return false;
-
- TransformPointInternal(inverse, point);
- return true;
+absl::optional<PointF> Transform::InverseMapPoint(const PointF& point) const {
+ if (LIKELY(!full_matrix_)) {
+ if (!axis_2d_.IsInvertible())
+ return absl::nullopt;
+ return axis_2d_.InverseMapPoint(point);
+ }
+ Matrix44 inverse(Matrix44::kUninitialized);
+ if (!matrix_.GetInverse(inverse))
+ return absl::nullopt;
+ return MapPointInternal(inverse, point);
}
-bool Transform::TransformPointReverse(Point3F* point) const {
- DCHECK(point);
-
- // TODO(sad): Try to avoid trying to invert the matrix.
- skia::Matrix44 inverse(skia::Matrix44::kUninitialized_Constructor);
- if (!matrix_.invert(&inverse))
- return false;
-
- TransformPointInternal(inverse, point);
- return true;
+absl::optional<Point> Transform::InverseMapPoint(const Point& point) const {
+ if (absl::optional<PointF> point_f = InverseMapPoint(PointF(point)))
+ return ToRoundedPoint(*point_f);
+ return absl::nullopt;
}
-void Transform::TransformRect(RectF* rect) const {
- if (matrix_.isIdentity())
- return;
-
- SkRect src = RectFToSkRect(*rect);
- SkMatrix(matrix_).mapRect(&src);
- *rect = SkRectToRectF(src);
+absl::optional<Point3F> Transform::InverseMapPoint(const Point3F& point) const {
+ if (LIKELY(!full_matrix_)) {
+ if (!axis_2d_.IsInvertible())
+ return absl::nullopt;
+ PointF result = axis_2d_.InverseMapPoint(point.AsPointF());
+ return Point3F(result.x(), result.y(), ClampFloatGeometry(point.z()));
+ }
+ Matrix44 inverse(Matrix44::kUninitialized);
+ if (!matrix_.GetInverse(inverse))
+ return absl::nullopt;
+ return absl::make_optional(MapPointInternal(inverse, point));
}
-bool Transform::TransformRectReverse(RectF* rect) const {
- if (matrix_.isIdentity())
- return true;
+RectF Transform::MapRect(const RectF& rect) const {
+ if (IsIdentity())
+ return rect;
- skia::Matrix44 inverse(skia::Matrix44::kUninitialized_Constructor);
- if (!matrix_.invert(&inverse))
- return false;
+ if (LIKELY(!full_matrix_) && axis_2d_.scale().x() >= 0 &&
+ axis_2d_.scale().y() >= 0) {
+ return axis_2d_.MapRect(rect);
+ }
- SkRect src = RectFToSkRect(*rect);
- SkMatrix(inverse).mapRect(&src);
- *rect = SkRectToRectF(src);
- return true;
+ return MapQuad(QuadF(rect)).BoundingBox();
}
-bool Transform::TransformRRectF(RRectF* rrect) const {
- SkRRect result;
- if (!SkRRect(*rrect).transform(SkMatrix(matrix_), &result))
- return false;
- *rrect = gfx::RRectF(result);
- return true;
+Rect Transform::MapRect(const Rect& rect) const {
+ if (IsIdentity())
+ return rect;
+
+ return ToEnclosingRect(MapRect(RectF(rect)));
}
-void Transform::TransformBox(BoxF* box) const {
+absl::optional<RectF> Transform::InverseMapRect(const RectF& rect) const {
+ if (IsIdentity())
+ return rect;
+
+ if (LIKELY(!full_matrix_)) {
+ if (!axis_2d_.IsInvertible())
+ return absl::nullopt;
+ if (axis_2d_.scale().x() > 0 && axis_2d_.scale().y() > 0)
+ return axis_2d_.InverseMapRect(rect);
+ }
+
+ Transform inverse;
+ if (!GetInverse(&inverse))
+ return absl::nullopt;
+
+ return inverse.MapQuad(QuadF(rect)).BoundingBox();
+}
+
+absl::optional<Rect> Transform::InverseMapRect(const Rect& rect) const {
+ if (IsIdentity())
+ return rect;
+
+ if (absl::optional<RectF> mapped = InverseMapRect(RectF(rect)))
+ return ToEnclosingRect(mapped.value());
+ return absl::nullopt;
+}
+
+BoxF Transform::MapBox(const BoxF& box) const {
BoxF bounds;
bool first_point = true;
for (int corner = 0; corner < 8; ++corner) {
- gfx::Point3F point = box->origin();
- point += gfx::Vector3dF(corner & 1 ? box->width() : 0.f,
- corner & 2 ? box->height() : 0.f,
- corner & 4 ? box->depth() : 0.f);
- TransformPoint(&point);
+ gfx::Point3F point = box.origin();
+ point += gfx::Vector3dF(corner & 1 ? box.width() : 0.f,
+ corner & 2 ? box.height() : 0.f,
+ corner & 4 ? box.depth() : 0.f);
+ point = MapPoint(point);
if (first_point) {
bounds.set_origin(point);
first_point = false;
@@ -508,127 +794,292 @@
bounds.ExpandTo(point);
}
}
- *box = bounds;
+ return bounds;
}
-bool Transform::TransformBoxReverse(BoxF* box) const {
- gfx::Transform inverse = *this;
- if (!GetInverse(&inverse))
- return false;
- inverse.TransformBox(box);
- return true;
+QuadF Transform::MapQuad(const QuadF& quad) const {
+ return QuadF(MapPoint(quad.p1()), MapPoint(quad.p2()), MapPoint(quad.p3()),
+ MapPoint(quad.p4()));
+}
+
+PointF Transform::ProjectPoint(const PointF& point, bool* clamped) const {
+ // This is basically ray-tracing. We have a point in the destination plane
+ // with z=0, and we cast a ray parallel to the z-axis from that point to find
+ // the z-position at which it intersects the z=0 plane with the transform
+ // applied. Once we have that point we apply the inverse transform to find
+ // the corresponding point in the source space.
+ //
+ // Given a plane with normal Pn, and a ray starting at point R0 and with
+ // direction defined by the vector Rd, we can find the intersection point as
+ // a distance d from R0 in units of Rd by:
+ //
+ // d = -dot (Pn', R0) / dot (Pn', Rd)
+
+ if (clamped)
+ *clamped = false;
+
+ if (LIKELY(!full_matrix_))
+ return axis_2d_.MapPoint(point);
+
+ if (!std::isnormal(matrix_.rc(2, 2))) {
+ // In this case, the projection plane is parallel to the ray we are trying
+ // to trace, and there is no well-defined value for the projection.
+ if (clamped)
+ *clamped = true;
+ return gfx::PointF();
+ }
+
+ double x = point.x();
+ double y = point.y();
+ double z = -(matrix_.rc(2, 0) * x + matrix_.rc(2, 1) * y + matrix_.rc(2, 3)) /
+ matrix_.rc(2, 2);
+ if (!std::isfinite(z)) {
+ // Same as the previous condition.
+ if (clamped)
+ *clamped = true;
+ return gfx::PointF();
+ }
+
+ double v[4] = {x, y, z, 1};
+ matrix_.MapVector4(v);
+
+ if (v[3] <= 0) {
+ // To represent infinity and ensure the bounding box of ProjectQuad() is
+ // accurate in both float, int and blink::LayoutUnit, we use a large but
+ // not-too-large number here when clamping.
+ constexpr double kBigNumber = 1 << (std::numeric_limits<float>::digits - 1);
+ if (clamped)
+ *clamped = true;
+ return PointF(std::copysign(kBigNumber, v[0]),
+ std::copysign(kBigNumber, v[1]));
+ }
+
+ if (v[3] != 1) {
+ v[0] /= v[3];
+ v[1] /= v[3];
+ }
+ return PointF(ClampFloatGeometry(v[0]), ClampFloatGeometry(v[1]));
+}
+
+QuadF Transform::ProjectQuad(const QuadF& quad) const {
+ bool clamped1 = false;
+ bool clamped2 = false;
+ bool clamped3 = false;
+ bool clamped4 = false;
+
+ QuadF projected_quad(
+ ProjectPoint(quad.p1(), &clamped1), ProjectPoint(quad.p2(), &clamped2),
+ ProjectPoint(quad.p3(), &clamped3), ProjectPoint(quad.p4(), &clamped4));
+
+ // If all points on the quad had w < 0, then the entire quad would not be
+ // visible to the projected surface.
+ if (clamped1 && clamped2 && clamped3 && clamped4)
+ return QuadF();
+
+ return projected_quad;
+}
+
+absl::optional<DecomposedTransform> Transform::Decompose() const {
+ if (LIKELY(!full_matrix_)) {
+ // Consider letting 2d decomposition always succeed.
+ if (!axis_2d_.IsInvertible())
+ return absl::nullopt;
+ return axis_2d_.Decompose();
+ }
+ return matrix_.Decompose();
+}
+
+// static
+Transform Transform::Compose(const DecomposedTransform& decomp) {
+ Transform result;
+
+ for (int i = 0; i < 3; i++) {
+ if (decomp.perspective[i] != 0)
+ result.set_rc(3, i, decomp.perspective[i]);
+ }
+ if (decomp.perspective[3] != 1)
+ result.set_rc(3, 3, decomp.perspective[3]);
+
+ result.Translate3d(decomp.translate[0], decomp.translate[1],
+ decomp.translate[2]);
+
+ result.PreConcat(Transform(decomp.quaternion));
+
+ if (decomp.skew[0] || decomp.skew[1] || decomp.skew[2])
+ result.EnsureFullMatrix().ApplyDecomposedSkews(decomp.skew);
+
+ result.Scale3d(decomp.scale[0], decomp.scale[1], decomp.scale[2]);
+
+ return result;
}
bool Transform::Blend(const Transform& from, double progress) {
- DecomposedTransform to_decomp;
- DecomposedTransform from_decomp;
- if (!DecomposeTransform(&to_decomp, *this) ||
- !DecomposeTransform(&from_decomp, from))
+ absl::optional<DecomposedTransform> to_decomp = Decompose();
+ if (!to_decomp)
+ return false;
+ absl::optional<DecomposedTransform> from_decomp = from.Decompose();
+ if (!from_decomp)
return false;
- to_decomp = BlendDecomposedTransforms(to_decomp, from_decomp, progress);
+ *to_decomp = BlendDecomposedTransforms(*to_decomp, *from_decomp, progress);
- matrix_ = ComposeTransform(to_decomp).matrix();
+ *this = Compose(*to_decomp);
return true;
}
-void Transform::RoundTranslationComponents() {
- matrix_.set(0, 3, std::round(matrix_.get(0, 3)));
- matrix_.set(1, 3, std::round(matrix_.get(1, 3)));
+bool Transform::Accumulate(const Transform& other) {
+ absl::optional<DecomposedTransform> this_decomp = Decompose();
+ if (!this_decomp)
+ return false;
+ absl::optional<DecomposedTransform> other_decomp = other.Decompose();
+ if (!other_decomp)
+ return false;
+
+ *this_decomp = AccumulateDecomposedTransforms(*this_decomp, *other_decomp);
+
+ *this = Compose(*this_decomp);
+ return true;
}
-void Transform::TransformPointInternal(const skia::Matrix44& xform,
- Point3F* point) const {
- if (xform.isIdentity())
- return;
-
- SkScalar p[4] = {point->x(), point->y(), point->z(), 1};
-
- xform.mapScalars(p);
-
- if (p[3] != SK_Scalar1 && p[3] != 0.f) {
- float w_inverse = SK_Scalar1 / p[3];
- point->SetPoint(p[0] * w_inverse, p[1] * w_inverse, p[2] * w_inverse);
+void Transform::Round2dTranslationComponents() {
+ if (LIKELY(!full_matrix_)) {
+ axis_2d_ = AxisTransform2d::FromScaleAndTranslation(
+ axis_2d_.scale(), Vector2dF(std::round(axis_2d_.translation().x()),
+ std::round(axis_2d_.translation().y())));
} else {
- point->SetPoint(p[0], p[1], p[2]);
+ matrix_.set_rc(0, 3, std::round(matrix_.rc(0, 3)));
+ matrix_.set_rc(1, 3, std::round(matrix_.rc(1, 3)));
}
}
-void Transform::TransformVectorInternal(const skia::Matrix44& xform,
- Vector3dF* vector) const {
- if (xform.isIdentity())
- return;
-
- SkScalar p[4] = {vector->x(), vector->y(), vector->z(), 0};
-
- xform.mapScalars(p);
-
- vector->set_x(p[0]);
- vector->set_y(p[1]);
- vector->set_z(p[2]);
+void Transform::RoundToIdentityOrIntegerTranslation() {
+ if (LIKELY(!full_matrix_)) {
+ axis_2d_ = AxisTransform2d::FromScaleAndTranslation(
+ Vector2dF(1, 1), Vector2dF(std::round(axis_2d_.translation().x()),
+ std::round(axis_2d_.translation().y())));
+ } else {
+ matrix_ =
+ Matrix44(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, // col0-2
+ std::round(matrix_.rc(0, 3)), // col3
+ std::round(matrix_.rc(1, 3)), std::round(matrix_.rc(2, 3)), 1);
+ }
}
-void Transform::TransformPointInternal(const skia::Matrix44& xform,
- PointF* point) const {
- if (xform.isIdentity())
- return;
+PointF Transform::MapPointInternal(const Matrix44& matrix,
+ const PointF& point) const {
+ DCHECK(full_matrix_);
- SkScalar p[4] = {SkIntToScalar(point->x()), SkIntToScalar(point->y()), 0, 1};
+ double p[2] = {point.x(), point.y()};
- xform.mapScalars(p);
+ double w = matrix.MapVector2(p);
- point->SetPoint(p[0], p[1]);
+ if (w != 1.0 && std::isnormal(w)) {
+ double w_inverse = 1.0 / w;
+ return PointF(ClampFloatGeometry(p[0] * w_inverse),
+ ClampFloatGeometry(p[1] * w_inverse));
+ }
+ return PointF(ClampFloatGeometry(p[0]), ClampFloatGeometry(p[1]));
}
-void Transform::TransformPointInternal(const skia::Matrix44& xform,
- Point* point) const {
- PointF point_float(*point);
- TransformPointInternal(xform, &point_float);
- *point = ToRoundedPoint(point_float);
+Point3F Transform::MapPointInternal(const Matrix44& matrix,
+ const Point3F& point) const {
+ DCHECK(full_matrix_);
+
+ double p[4] = {point.x(), point.y(), point.z(), 1};
+
+ matrix.MapVector4(p);
+
+ if (p[3] != 1.0 && std::isnormal(p[3])) {
+ double w_inverse = 1.0 / p[3];
+ return Point3F(ClampFloatGeometry(p[0] * w_inverse),
+ ClampFloatGeometry(p[1] * w_inverse),
+ ClampFloatGeometry(p[2] * w_inverse));
+ }
+ return Point3F(ClampFloatGeometry(p[0]), ClampFloatGeometry(p[1]),
+ ClampFloatGeometry(p[2]));
}
-bool Transform::ApproximatelyEqual(const gfx::Transform& transform) const {
- static const float component_tolerance = 0.1f;
+bool Transform::ApproximatelyEqual(const gfx::Transform& transform,
+ float abs_translation_tolerance,
+ float abs_other_tolerance,
+ float rel_scale_tolerance) const {
+ if (*this == transform)
+ return true;
- // We may have a larger discrepancy in the scroll components due to snapping
- // (floating point error might round the other way).
- static const float translation_tolerance = 1.f;
+ if (abs_translation_tolerance == 0 && abs_other_tolerance == 0)
+ return false;
+
+ auto approximately_equal = [abs_other_tolerance](float a, float b) {
+ return std::abs(a - b) <= abs_other_tolerance;
+ };
+ auto translation_approximately_equal = [abs_translation_tolerance](float a,
+ float b) {
+ return std::abs(a - b) <= abs_translation_tolerance;
+ };
+ auto scale_approximately_equal = [abs_other_tolerance, rel_scale_tolerance](
+ float a, float b) {
+ float diff = std::abs(a - b);
+ return diff <= abs_other_tolerance &&
+ (rel_scale_tolerance == 0 ||
+ diff <= (std::abs(a) + std::abs(b)) * rel_scale_tolerance);
+ };
+
+ if (LIKELY(!full_matrix_) && LIKELY(!transform.full_matrix_)) {
+ return scale_approximately_equal(axis_2d_.scale().x(),
+ transform.axis_2d_.scale().x()) &&
+ scale_approximately_equal(axis_2d_.scale().y(),
+ transform.axis_2d_.scale().y()) &&
+ translation_approximately_equal(
+ axis_2d_.translation().x(),
+ transform.axis_2d_.translation().x()) &&
+ translation_approximately_equal(
+ axis_2d_.translation().y(),
+ transform.axis_2d_.translation().y());
+ }
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 4; col++) {
- const float delta =
- std::abs(matrix().get(row, col) - transform.matrix().get(row, col));
- const float tolerance =
- col == 3 && row < 3 ? translation_tolerance : component_tolerance;
- if (delta > tolerance)
+ float x = rc(row, col);
+ float y = transform.rc(row, col);
+ if (row < 3 && col == 3) {
+ if (!translation_approximately_equal(x, y))
+ return false;
+ } else if (row < 3 && col == row) {
+ if (!scale_approximately_equal(x, y))
+ return false;
+ } else if (!approximately_equal(x, y)) {
return false;
+ }
}
}
-
return true;
}
std::string Transform::ToString() const {
return base::StringPrintf(
- "[ %+0.4f %+0.4f %+0.4f %+0.4f \n"
- " %+0.4f %+0.4f %+0.4f %+0.4f \n"
- " %+0.4f %+0.4f %+0.4f %+0.4f \n"
- " %+0.4f %+0.4f %+0.4f %+0.4f ]\n",
- matrix_.get(0, 0), matrix_.get(0, 1), matrix_.get(0, 2),
- matrix_.get(0, 3), matrix_.get(1, 0), matrix_.get(1, 1),
- matrix_.get(1, 2), matrix_.get(1, 3), matrix_.get(2, 0),
- matrix_.get(2, 1), matrix_.get(2, 2), matrix_.get(2, 3),
- matrix_.get(3, 0), matrix_.get(3, 1), matrix_.get(3, 2),
- matrix_.get(3, 3));
+ "[ %lg %lg %lg %lg\n"
+ " %lg %lg %lg %lg\n"
+ " %lg %lg %lg %lg\n"
+ " %lg %lg %lg %lg ]\n",
+ rc(0, 0), rc(0, 1), rc(0, 2), rc(0, 3), rc(1, 0), rc(1, 1), rc(1, 2),
+ rc(1, 3), rc(2, 0), rc(2, 1), rc(2, 2), rc(2, 3), rc(3, 0), rc(3, 1),
+ rc(3, 2), rc(3, 3));
}
-SkM44 Transform::GetMatrixAsSkM44() const {
- return SkM44(matrix_.get(0, 0), matrix_.get(0, 1), matrix_.get(0, 2),
- matrix_.get(0, 3), matrix_.get(1, 0), matrix_.get(1, 1),
- matrix_.get(1, 2), matrix_.get(1, 3), matrix_.get(2, 0),
- matrix_.get(2, 1), matrix_.get(2, 2), matrix_.get(2, 3),
- matrix_.get(3, 0), matrix_.get(3, 1), matrix_.get(3, 2),
- matrix_.get(3, 3));
+std::string Transform::ToDecomposedString() const {
+ absl::optional<gfx::DecomposedTransform> decomp = Decompose();
+ if (!decomp)
+ return ToString() + "(degenerate)";
+
+ if (IsIdentity())
+ return "identity";
+
+ if (IsIdentityOrTranslation()) {
+ return base::StringPrintf("translate: %lg,%lg,%lg", decomp->translate[0],
+ decomp->translate[1], decomp->translate[2]);
+ }
+
+ return decomp->ToString();
}
} // namespace gfx
diff --git a/ui/gfx/geometry/transform.h b/ui/gfx/geometry/transform.h
index e0df4d6..27068ae 100644
--- a/ui/gfx/geometry/transform.h
+++ b/ui/gfx/geometry/transform.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,84 +6,222 @@
#define UI_GFX_GEOMETRY_TRANSFORM_H_
#include <iosfwd>
+#include <memory>
#include <string>
-#include "base/compiler_specific.h"
-#include "skia/ext/skia_matrix_44.h"
-#include "third_party/skia/include/core/SkM44.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/geometry/axis_transform2d.h"
#include "ui/gfx/geometry/geometry_skia_export.h"
-#include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/gfx/geometry/matrix44.h"
namespace gfx {
class BoxF;
+class Rect;
class RectF;
-class RRectF;
class Point;
class PointF;
class Point3F;
+class QuadF;
class Quaternion;
+class Vector2dF;
class Vector3dF;
+struct DecomposedTransform;
-// 4x4 transformation matrix. Transform is cheap and explicitly allows
-// copy/assign.
+// 4x4 Transformation matrix. Depending on the complexity of the matrix, it may
+// be internally stored as an AxisTransform2d (float precision) or a full
+// Matrix44 (4x4 double precision). Which one is used only affects precision and
+// performance.
+// - On construction (including constructors and static functions returning a
+// new Transform object), AxisTransform2d will be used if it the matrix will
+// be 2d scale and/or translation, otherwise Matrix44, with some exceptions
+// (e.g. ColMajor()) described in the method comments.
+// - On mutation, if the matrix has been using AxisTransform2d and the result
+// can still be 2d scale and/or translation, AxisTransform2d will still be
+// used, otherwise Matrix44, with some exceptions (e.g. set_rc()) described
+// in the method comments.
+// - On assignment, the new matrix will keep the choice of the rhs matrix.
+//
class GEOMETRY_SKIA_EXPORT Transform {
public:
- enum SkipInitialization { kSkipInitialization };
+ constexpr Transform() : axis_2d_() {}
- constexpr Transform() : matrix_(skia::Matrix44::kIdentity_Constructor) {}
+ explicit Transform(const AxisTransform2d& axis_2d) : axis_2d_(axis_2d) {}
- // Skips initializing this matrix to avoid overhead, when we know it will be
- // initialized before use.
- explicit Transform(SkipInitialization)
- : matrix_(skia::Matrix44::kUninitialized_Constructor) {}
- Transform(const Transform& rhs) = default;
- Transform& operator=(const Transform& rhs) = default;
- // Initialize with the concatenation of lhs * rhs.
- Transform(const Transform& lhs, const Transform& rhs)
- : matrix_(lhs.matrix_, rhs.matrix_) {}
- explicit Transform(const skia::Matrix44& matrix) : matrix_(matrix) {}
- explicit Transform(const SkMatrix& matrix)
- : matrix_(skia::Matrix44(matrix)) {}
- // Constructs a transform from explicit 16 matrix elements. Elements
- // should be given in row-major order.
- Transform(SkScalar col1row1,
- SkScalar col2row1,
- SkScalar col3row1,
- SkScalar col4row1,
- SkScalar col1row2,
- SkScalar col2row2,
- SkScalar col3row2,
- SkScalar col4row2,
- SkScalar col1row3,
- SkScalar col2row3,
- SkScalar col3row3,
- SkScalar col4row3,
- SkScalar col1row4,
- SkScalar col2row4,
- SkScalar col3row4,
- SkScalar col4row4);
- // Constructs a transform from explicit 2d elements. All other matrix
- // elements remain the same as the corresponding elements of an identity
- // matrix.
- Transform(SkScalar col1row1,
- SkScalar col2row1,
- SkScalar col1row2,
- SkScalar col2row2,
- SkScalar x_translation,
- SkScalar y_translation);
+ // Creates a transform from explicit 16 matrix elements in row-major order.
+ // Always creates a double precision 4x4 matrix.
+ // clang-format off
+ static constexpr Transform RowMajor(
+ double r0c0, double r0c1, double r0c2, double r0c3,
+ double r1c0, double r1c1, double r1c2, double r1c3,
+ double r2c0, double r2c1, double r2c2, double r2c3,
+ double r3c0, double r3c1, double r3c2, double r3c3) {
+ return Transform(r0c0, r1c0, r2c0, r3c0, // col 0
+ r0c1, r1c1, r2c1, r3c1, // col 1
+ r0c2, r1c2, r2c2, r3c2, // col 2
+ r0c3, r1c3, r2c3, r3c3); // col 3
+ }
+
+ // Creates a transform from explicit 16 matrix elements in col-major order.
+ // Always creates a double precision 4x4 matrix.
+ // See also ColMajor(double[]) and ColMajorF(float[]).
+ static constexpr Transform ColMajor(
+ double r0c0, double r1c0, double r2c0, double r3c0,
+ double r0c1, double r1c1, double r2c1, double r3c1,
+ double r0c2, double r1c2, double r2c2, double r3c2,
+ double r0c3, double r1c3, double r2c3, double r3c3) {
+ return Transform(r0c0, r1c0, r2c0, r3c0, // col 0
+ r0c1, r1c1, r2c1, r3c1, // col 1
+ r0c2, r1c2, r2c2, r3c2, // col 2
+ r0c3, r1c3, r2c3, r3c3); // col 3
+ }
+ // clang-format on
+
+ // Creates a transform from explicit 2d elements. All other matrix elements
+ // remain the same as the corresponding elements of an identity matrix.
+ // Always creates a double precision 4x4 matrix.
+ // TODO(crbug.com/1359528): Revisit the above statement. Evaluate performance
+ // and precision requirements of SVG and CSS transform:matrix().
+ static constexpr Transform Affine(double a, // a.k.a. r0c0 or scale_x
+ double b, // a.k.a. r1c0 or tan(skew_y)
+ double c, // a.k.a. r0c1 or tan(skew_x)
+ double d, // a.k.a r1c1 or scale_y
+ double e, // a.k.a r0c3 or translation_x
+ double f) { // a.k.a r1c3 or translaiton_y
+ return ColMajor(a, b, 0, 0, c, d, 0, 0, 0, 0, 1, 0, e, f, 0, 1);
+ }
// Constructs a transform corresponding to the given quaternion.
explicit Transform(const Quaternion& q);
- bool operator==(const Transform& rhs) const { return matrix_ == rhs.matrix_; }
- bool operator!=(const Transform& rhs) const { return matrix_ != rhs.matrix_; }
+ // Creates a transform as a 2d translation.
+ static constexpr Transform MakeTranslation(float tx, float ty) {
+ return Transform(1, 1, tx, ty);
+ }
+ static Transform MakeTranslation(const Vector2dF& v) {
+ return MakeTranslation(v.x(), v.y());
+ }
+
+ // Creates a transform as a 2d scale.
+ static constexpr Transform MakeScale(float scale) {
+ return MakeScale(scale, scale);
+ }
+ static constexpr Transform MakeScale(float sx, float sy) {
+ return Transform(sx, sy, 0, 0);
+ }
+
+ // Accurately rotate by 90, 180 or 270 degrees about the z axis.
+ static constexpr Transform Make90degRotation() {
+ return Affine(0, 1, -1, 0, 0, 0);
+ }
+ static constexpr Transform Make180degRotation() { return MakeScale(-1); }
+ static constexpr Transform Make270degRotation() {
+ return Affine(0, -1, 1, 0, 0, 0);
+ }
// Resets this transform to the identity transform.
- void MakeIdentity() { matrix_.setIdentity(); }
+ void MakeIdentity() {
+ full_matrix_ = false;
+ axis_2d_ = AxisTransform2d();
+ }
+
+ bool operator==(const Transform& rhs) const {
+ if (LIKELY(!full_matrix_ && !rhs.full_matrix_))
+ return axis_2d_ == rhs.axis_2d_;
+ if (full_matrix_ && rhs.full_matrix_)
+ return matrix_ == rhs.matrix_;
+ return GetFullMatrix() == rhs.GetFullMatrix();
+ }
+ bool operator!=(const Transform& rhs) const { return !(*this == rhs); }
+
+ // Gets a value at |row|, |col| from the matrix.
+ constexpr double rc(int row, int col) const {
+ DCHECK_LE(static_cast<unsigned>(row), 3u);
+ DCHECK_LE(static_cast<unsigned>(col), 3u);
+ if (LIKELY(!full_matrix_)) {
+ float m[4][4] = {{axis_2d_.scale().x(), 0, 0, axis_2d_.translation().x()},
+ {0, axis_2d_.scale().y(), 0, axis_2d_.translation().y()},
+ {0, 0, 1, 0},
+ {0, 0, 0, 1}};
+ return m[row][col];
+ }
+ return matrix_.rc(row, col);
+ }
+
+ // Sets a value in the matrix at |row|, |col|. It forces full double precision
+ // 4x4 matrix.
+ void set_rc(int row, int col, double v) {
+ DCHECK_LE(static_cast<unsigned>(row), 3u);
+ DCHECK_LE(static_cast<unsigned>(col), 3u);
+ EnsureFullMatrix().set_rc(row, col, v);
+ }
+
+ // Constructs Transform from a double col-major array.
+ // Always creates a double precision 4x4 matrix.
+ static Transform ColMajor(const double a[16]);
+
+ // Constructs Transform from a float col-major array. Creates an
+ // AxisTransform2d or a Matrix44 depending on the values. GetColMajorF() and
+ // ColMajorF() are used when passing a Transform through mojo.
+ static Transform ColMajorF(const float a[16]);
+
+ // Gets col-major data.
+ void GetColMajor(double a[16]) const;
+ void GetColMajorF(float a[16]) const;
+ double ColMajorData(int index) const { return rc(index % 4, index / 4); }
+
+ // Applies a transformation on the current transformation,
+ // i.e. this = this * transform.
+ // "Pre" here means |this| is before the operator in the expression.
+ // Corresponds to DOMMatrix.multiplySelf().
+ void PreConcat(const Transform& transform);
+
+ // Applies a transformation on the current transformation,
+ // i.e. this = transform * this.
+ // Corresponds to DOMMatrix.preMultiplySelf() (note the difference about
+ // "Pre" and "Post"). "Post" here means |this| is after the operator in the
+ // expression.
+ void PostConcat(const Transform& transform);
+
+ // Applies a 2d-axis transform on the current transformation,
+ // i.e. this = this * transform.
+ void PreConcat(const AxisTransform2d& transform);
+
+ // Applies a transformation on the current transformation,
+ // i.e. this = transform * this.
+ void PostConcat(const AxisTransform2d& transform);
+
+ // Applies the current transformation on a scaling and assigns the result
+ // to |this|, i.e. this = this * scaling.
+ void Scale(float scale) { Scale(scale, scale); }
+ void Scale(float x, float y);
+ void Scale3d(float x, float y, float z);
+
+ // Applies a scale to the current transformation and assigns the result to
+ // |this|, i.e. this = scaling * this.
+ void PostScale(float scale) { PostScale(scale, scale); }
+ void PostScale(float x, float y);
+ void PostScale3d(float x, float y, float z);
+
+ // Applies the current transformation on a translation and assigns the result
+ // to |this|, i.e. this = this * translation.
+ void Translate(const Vector2dF& offset);
+ void Translate(float x, float y);
+ void Translate3d(const Vector3dF& offset);
+ void Translate3d(float x, float y, float z);
+
+ // Applies a translation to the current transformation and assigns the result
+ // to |this|, i.e. this = translation * this.
+ void PostTranslate(const Vector2dF& offset);
+ void PostTranslate(float x, float y);
+ void PostTranslate3d(const Vector3dF& offset);
+ void PostTranslate3d(float x, float y, float z);
+
+ // The following methods have the "Pre" semantics,
+ // i.e. this = this * operation.
// Applies the current transformation on a 2d rotation and assigns the result
- // to |this|.
+ // to |this|, i.e. this = this * rotation.
void Rotate(double degrees) { RotateAboutZAxis(degrees); }
// Applies the current transformation on an axis-angle rotation and assigns
@@ -91,84 +229,83 @@
void RotateAboutXAxis(double degrees);
void RotateAboutYAxis(double degrees);
void RotateAboutZAxis(double degrees);
+ void RotateAbout(double x, double y, double z, double degrees);
void RotateAbout(const Vector3dF& axis, double degrees);
- // Applies the current transformation on a scaling and assigns the result
- // to |this|.
- void Scale(SkScalar x, SkScalar y);
- void Scale3d(SkScalar x, SkScalar y, SkScalar z);
- gfx::Vector2dF Scale2d() const {
- return gfx::Vector2dF(matrix_.get(0, 0), matrix_.get(1, 1));
- }
-
- // Applies a scale to the current transformation and assigns the result to
- // |this|.
- void PostScale(SkScalar x, SkScalar y);
-
- // Applies the current transformation on a translation and assigns the result
- // to |this|.
- void Translate(const Vector2dF& offset);
- void Translate(SkScalar x, SkScalar y);
- void Translate3d(const Vector3dF& offset);
- void Translate3d(SkScalar x, SkScalar y, SkScalar z);
-
- // Applies a translation to the current transformation and assigns the result
- // to |this|.
- void PostTranslate(const Vector2dF& offset);
- void PostTranslate(SkScalar x, SkScalar y);
-
// Applies the current transformation on a skew and assigns the result
- // to |this|.
- void Skew(double angle_x, double angle_y);
+ // to |this|, i.e. this = this * skew.
+ void Skew(double degrees_x, double degrees_y);
+ void SkewX(double degrees) { Skew(degrees, 0); }
+ void SkewY(double degrees) { Skew(0, degrees); }
// Applies the current transformation on a perspective transform and assigns
// the result to |this|.
- void ApplyPerspectiveDepth(SkScalar depth);
-
- // Applies a transformation on the current transformation
- // (i.e. 'this = this * transform;').
- void PreconcatTransform(const Transform& transform);
-
- // Applies a transformation on the current transformation
- // (i.e. 'this = transform * this;').
- void ConcatTransform(const Transform& transform);
+ void ApplyPerspectiveDepth(double depth);
// Returns true if this is the identity matrix.
// This function modifies a mutable variable in |matrix_|.
- bool IsIdentity() const { return matrix_.isIdentity(); }
+ bool IsIdentity() const {
+ return LIKELY(!full_matrix_) ? axis_2d_ == AxisTransform2d()
+ : matrix_.IsIdentity();
+ }
// Returns true if the matrix is either identity or pure translation.
- bool IsIdentityOrTranslation() const { return matrix_.isTranslate(); }
+ bool IsIdentityOrTranslation() const {
+ return LIKELY(!full_matrix_) ? axis_2d_.scale() == Vector2dF(1, 1)
+ : matrix_.IsIdentityOrTranslation();
+ }
// Returns true if the matrix is either the identity or a 2d translation.
- bool IsIdentityOr2DTranslation() const {
- return matrix_.isTranslate() && matrix_.get(2, 3) == 0;
+ bool IsIdentityOr2dTranslation() const {
+ return LIKELY(!full_matrix_)
+ ? axis_2d_.scale() == Vector2dF(1, 1)
+ : matrix_.IsIdentityOrTranslation() && matrix_.rc(2, 3) == 0;
}
// Returns true if the matrix is either identity or pure translation,
// allowing for an amount of inaccuracy as specified by the parameter.
- bool IsApproximatelyIdentityOrTranslation(SkScalar tolerance) const;
- bool IsApproximatelyIdentityOrIntegerTranslation(SkScalar tolerance) const;
+ bool IsApproximatelyIdentityOrTranslation(double tolerance) const;
+ bool IsApproximatelyIdentityOrIntegerTranslation(double tolerance) const;
// Returns true if the matrix is either a positive scale and/or a translation.
bool IsPositiveScaleOrTranslation() const {
- if (!IsScaleOrTranslation())
+ if (LIKELY(!full_matrix_))
+ return axis_2d_.scale().x() > 0.0 && axis_2d_.scale().y() > 0.0;
+
+ if (!matrix_.IsScaleOrTranslation())
return false;
- return matrix_.get(0, 0) > 0.0 && matrix_.get(1, 1) > 0.0 &&
- matrix_.get(2, 2) > 0.0;
+ return matrix_.rc(0, 0) > 0.0 && matrix_.rc(1, 1) > 0.0 &&
+ matrix_.rc(2, 2) > 0.0;
}
+ // Returns true if the matrix is 2d scale or translation, and if it has scale,
+ // the scale proportionally scales up in x and y directions. This function
+ // allows rare false-negatives.
+ bool Is2dProportionalUpscaleAndOr2dTranslation() const;
+
// Returns true if the matrix is identity or, if the matrix consists only
// of a translation whose components can be represented as integers. Returns
// false if the translation contains a fractional component or is too large to
// fit in an integer.
bool IsIdentityOrIntegerTranslation() const;
+ bool IsIdentityOrInteger2dTranslation() const;
- // Returns true if the matrix had only scaling components.
- bool IsScale2d() const { return matrix_.isScale(); }
+ // Returns whether this matrix can transform a z=0 plane to something
+ // containing points where z != 0. This is primarily intended for metrics.
+ bool Creates3d() const;
- // Returns true if the matrix is has only scaling and translation components.
- bool IsScaleOrTranslation() const { return matrix_.isScaleTranslate(); }
+ // Returns true if the matrix has only x and y scaling components, including
+ // identity.
+ bool IsScale2d() const {
+ return LIKELY(!full_matrix_) ? axis_2d_.translation().IsZero()
+ : matrix_.IsScale() && matrix_.rc(2, 2) == 1;
+ }
+
+ // Returns true if the matrix is has only scaling and translation components,
+ // including identity.
+ bool IsScaleOrTranslation() const {
+ return LIKELY(!full_matrix_) || matrix_.IsScaleOrTranslation();
+ }
// Returns true if axis-aligned 2d rects will remain axis-aligned after being
// transformed by this matrix.
@@ -182,22 +319,46 @@
// Returns true if the matrix has any perspective component that would
// change the w-component of a homogeneous point.
- bool HasPerspective() const { return matrix_.hasPerspective(); }
+ bool HasPerspective() const {
+ return UNLIKELY(full_matrix_) && matrix_.HasPerspective();
+ }
// Returns true if this transform is non-singular.
- bool IsInvertible() const { return matrix_.invert(nullptr); }
+ bool IsInvertible() const {
+ return LIKELY(!full_matrix_) ? axis_2d_.IsInvertible()
+ : matrix_.IsInvertible();
+ }
+
+ // If |this| is invertible, inverts |this| and stores the result in
+ // |*transform|, and returns true. Otherwise sets |*transform| to identity
+ // and returns false.
+ [[nodiscard]] bool GetInverse(Transform* transform) const;
+
+ // Same as above except that it assumes success, otherwise DCHECK fails.
+ // This is suitable when the transform is known to be invertible.
+ [[nodiscard]] Transform GetCheckedInverse() const;
+
+ // Same as GetInverse() except that it returns the the inverse of |this| or
+ // identity, instead of a bool. This is suitable when it's good to fallback
+ // to identity silently.
+ [[nodiscard]] Transform InverseOrIdentity() const;
// Returns true if a layer with a forward-facing normal of (0, 0, 1) would
// have its back side facing frontwards after applying the transform.
bool IsBackFaceVisible() const;
- // Inverts the transform which is passed in. Returns true if successful, or
- // sets |transform| to the identify matrix on failure.
- bool GetInverse(Transform* transform) const WARN_UNUSED_RESULT;
-
// Transposes this transform in place.
void Transpose();
+ // Changes the transform to apply as if the origin were at (x, y, z).
+ void ApplyTransformOrigin(float x, float y, float z);
+
+ // Changes the transform to:
+ // scale3d(z, z, z) * mat * scale3d(1/z, 1/z, 1/z)
+ // Useful for mapping zoomed points to their zoomed transformed result:
+ // new_mat * (scale3d(z, z, z) * x) == scale3d(z, z, z) * (mat * x)
+ void Zoom(float zoom_factor);
+
// Set 3rd row and 3rd column to (0, 0, 1, 0). Note that this flattening
// operation is not quite the same as an orthographic projection and is
// technically not a linear operation.
@@ -212,111 +373,238 @@
// preserves the effect that any subsequent (multiplied from the right)
// transforms would have on z values.
//
- void FlattenTo2d();
+ void Flatten();
// Returns true if the 3rd row and 3rd column are both (0, 0, 1, 0).
bool IsFlat() const;
- // Returns the x and y translation components of the matrix.
+ // Returns true if the transform is flat and doesn't have perspective.
+ bool Is2dTransform() const;
+
+ // Returns the x and y translation components of the matrix, clamped with
+ // ClampFloatGeometry().
Vector2dF To2dTranslation() const;
- // Applies the transformation to the point.
- void TransformPoint(Point3F* point) const;
+ // Returns the x, y and z translation components of the matrix, clampe with
+ // ClampFloatGeometry().
+ Vector3dF To3dTranslation() const;
- // Applies the transformation to the point.
- void TransformPoint(PointF* point) const;
+ // Returns the x and y scale components of the matrix, clamped with
+ // ClampFloatGeometry().
+ Vector2dF To2dScale() const;
- // Applies the transformation to the point.
- void TransformPoint(Point* point) const;
+ // Returns the point with the transformation applied to |point|, clamped
+ // with ClampFloatGeometry().
+ [[nodiscard]] Point3F MapPoint(const Point3F& point) const;
+ // Maps [point.x(), point.y(), 0] to [result.x(), result.y(), discarded_z].
+ [[nodiscard]] PointF MapPoint(const PointF& point) const;
+ [[nodiscard]] Point MapPoint(const Point& point) const;
- // Applies the transformation to the vector.
- void TransformVector(Vector3dF* vector) const;
+ // Returns the vector with the transformation applied to |vector|, clamped
+ // with ClampFloatGeometry(). It differs from MapPoint() by that the
+ // translation and perspective components of the matrix are ignored.
+ [[nodiscard]] Vector3dF MapVector(const Vector3dF& vector) const;
- // Applies the reverse transformation on the point. Returns true if the
- // transformation can be inverted.
- bool TransformPointReverse(Point3F* point) const;
+ // Applies the transformation to the vector. The results are clamped with
+ // ClampFloatGeometry().
+ void TransformVector4(float vector[4]) const;
- // Applies the reverse transformation on the point. Returns true if the
- // transformation can be inverted. Rounds the result to the nearest point.
- bool TransformPointReverse(Point* point) const;
+ // Returns the point with reverse transformation applied to `point`, clamped
+ // with ClampFloatGeometry(), or `absl::nullopt` if the transformation cannot
+ // be inverted.
+ [[nodiscard]] absl::optional<PointF> InverseMapPoint(
+ const PointF& point) const;
+ [[nodiscard]] absl::optional<Point3F> InverseMapPoint(
+ const Point3F& point) const;
- // Applies transformation on the given rect. After the function completes,
- // |rect| will be the smallest axis aligned bounding rect containing the
- // transformed rect.
- void TransformRect(RectF* rect) const;
+ // Applies the reverse transformation on `point`. Returns `absl::nullopt` if
+ // the transformation cannot be inverted. Rounds the result to the nearest
+ // point.
+ [[nodiscard]] absl::optional<Point> InverseMapPoint(const Point& point) const;
- // Applies the reverse transformation on the given rect. After the function
- // completes, |rect| will be the smallest axis aligned bounding rect
- // containing the transformed rect. Returns false if the matrix cannot be
- // inverted.
- bool TransformRectReverse(RectF* rect) const;
+ // Returns the rect that is the smallest axis aligned bounding rect
+ // containing the transformed rect, clamped with ClampFloatGeometry().
+ [[nodiscard]] RectF MapRect(const RectF& rect) const;
+ [[nodiscard]] Rect MapRect(const Rect& rect) const;
- // Applies transformation on the given |rrect|. Returns false if the transform
- // matrix cannot be applied to rrect.
- bool TransformRRectF(RRectF* rrect) const;
+ // Applies the reverse transformation on the given rect. Returns
+ // `absl::nullopt` if the transformation cannot be inverted, or the rect that
+ // is the smallest axis aligned bounding rect containing the transformed rect,
+ // clamped with ClampFloatGeometry().
+ [[nodiscard]] absl::optional<RectF> InverseMapRect(const RectF& rect) const;
+ [[nodiscard]] absl::optional<Rect> InverseMapRect(const Rect& rect) const;
- // Applies transformation on the given box. After the function completes,
- // |box| will be the smallest axis aligned bounding box containing the
- // transformed box.
- void TransformBox(BoxF* box) const;
+ // Returns the box with transformation applied on the given box. The returned
+ // box will be the smallest axis aligned bounding box containing the
+ // transformed box, clamped with ClampFloatGeometry().
+ [[nodiscard]] BoxF MapBox(const BoxF& box) const;
- // Applies the reverse transformation on the given box. After the function
- // completes, |box| will be the smallest axis aligned bounding box
- // containing the transformed box. Returns false if the matrix cannot be
- // inverted.
- bool TransformBoxReverse(BoxF* box) const;
+ // Applies transformation on the given quad by applying the transformation
+ // on each point of the quad.
+ [[nodiscard]] QuadF MapQuad(const QuadF& quad) const;
+
+ // Maps a point on the z=0 plane into a point on the plane with which the
+ // transform applied, by extending a ray perpendicular to the source plane and
+ // computing the local x,y position of the point where that ray intersects
+ // with the destination plane. If such a point exists, sets |*clamped| (if
+ // provided) to false and returns the point. Otherwise sets |*clamped| (if
+ // provided) to true and:
+ // - If the ray is parallel with the destination plane, returns PointF().
+ // - If the opposite ray intersects with the destination plane, returns
+ // a point containing signed big values (simulating infinities).
+ //
+ // See https://bit.ly/perspective-projection-clamping for an illustration of
+ // clamping with perspective.
+ //
+ // When |this| is invertible and the result |*clamped| is false, this
+ // function is equivalent to:
+ // inverse(flatten(inverse(this))).MapPoint(point)
+ // and
+ // MapPoint(Point3F(point.x(), point.y(), unknown_z)) to
+ // Point3F(result.x(), result.y(), 0).
+ [[nodiscard]] PointF ProjectPoint(const PointF& point,
+ bool* clamped = nullptr) const;
+
+ // Projects the four corners of the quad with ProjectPoint(). Returns an
+ // empty quad if all of the vertices are clamped.
+ [[nodiscard]] QuadF ProjectQuad(const QuadF& quad) const;
+
+ // Decomposes |this| into |decomp|. Returns nullopt if |this| can't be
+ // decomposed. |decomp| must be identity on input.
+ //
+ // Uses routines described in the following specs:
+ // 2d: https://www.w3.org/TR/css-transforms-1/#decomposing-a-2d-matrix
+ // 3d: https://www.w3.org/TR/css-transforms-2/#decomposing-a-3d-matrix
+ //
+ // Note: when the determinant is negative, the 2d spec calls for flipping one
+ // of the axis, while the general 3d spec calls for flipping all of the
+ // scales. The latter not only introduces rotation in the case of a trivial
+ // scale inversion, but causes transformed objects to needlessly shrink and
+ // grow as they transform through scale = 0 along multiple axes. Thus 2d
+ // transforms should follow the 2d spec regarding matrix decomposition.
+ absl::optional<DecomposedTransform> Decompose() const;
+
+ // Composes a transform from the given |decomp|, following the routines
+ // detailed in this specs:
+ // https://www.w3.org/TR/css-transforms-2/#recomposing-to-a-3d-matrix
+ static Transform Compose(const DecomposedTransform& decomp);
// Decomposes |this| and |from|, interpolates the decomposed values, and
- // sets |this| to the reconstituted result. Returns false if either matrix
- // can't be decomposed. Uses routines described in this spec:
- // http://www.w3.org/TR/css3-3d-transforms/.
+ // sets |this| to the reconstituted result. Returns false and leaves |this|
+ // unchanged if either matrix can't be decomposed.
+ // Uses routines described in this spec:
+ // https://www.w3.org/TR/css-transforms-2/#matrix-interpolation
//
- // Note: this call is expensive since we need to decompose the transform. If
- // you're going to be calling this rapidly (e.g., in an animation) you should
- // decompose once using gfx::DecomposeTransforms and reuse your
- // DecomposedTransform.
+ // Note: this call is expensive for complex transforms since we need to
+ // decompose the transforms. If you're going to be calling this rapidly
+ // (e.g., in an animation) for complex transforms, you should decompose once
+ // using Decompose() and reuse your DecomposedTransform with
+ // BlendDecomposedTransforms() (see transform_util.h).
bool Blend(const Transform& from, double progress);
- void RoundTranslationComponents();
+ // Decomposes |this| and |from|, accumulates the decomposed values, and
+ // sets |this| to the reconstituted result. Returns false and leaves |this|
+ // unchanged if either matrix can't be decomposed.
+ // Uses routines described in this spec:
+ // https://www.w3.org/TR/css-transforms-2/#combining-transform-lists.
+ //
+ // Note: this function has the same performance characteristics as Blend().
+ // When possible, you should also reuse DecomposedTransform with
+ // AccumulateDecomposedTransforms() (see transform_util.h).
+ bool Accumulate(const Transform& other);
+
+ double Determinant() const;
+
+ // Rounds 2d translation components rc(0, 3), rc(1, 3) to integers.
+ void Round2dTranslationComponents();
+
+ // Rounds translation components to integers, and all other components to
+ // identity. Normally this function is meaningful only if
+ // IsApproximatelyIdentityOrIntegerTranslation() is true.
+ void RoundToIdentityOrIntegerTranslation();
// Returns |this| * |other|.
- Transform operator*(const Transform& other) const {
- return Transform(*this, other);
- }
+ Transform operator*(const Transform& other) const;
// Sets |this| = |this| * |other|
Transform& operator*=(const Transform& other) {
- PreconcatTransform(other);
+ PreConcat(other);
return *this;
}
- // Returns the underlying matrix.
- const skia::Matrix44& matrix() const { return matrix_; }
- skia::Matrix44& matrix() { return matrix_; }
+ // Checks whether `this` approximately equals `transform`.
+ // Returns true if all following conditions are met:
+ // - For (x, y) in all translation components of (this, transform):
+ // abs(x - y) <= abs_translation_tolerance
+ // - For (x, y) in all other components of (this, transform):
+ // abs(x - y) <= abs_other_tolerance
+ // - If rel_scale_tolerance is not zero, for (x, y) in all scale components:
+ // abs(x - y) <= (abs(x) + abs(y)) * rel_scale_tolerance.
+ bool ApproximatelyEqual(const gfx::Transform& transform,
+ float abs_translation_tolerance,
+ float abs_other_tolerance,
+ float rel_scale_tolerance) const;
+ // Checks approximate equality with one tolerance for all components.
+ bool ApproximatelyEqual(const gfx::Transform& transform,
+ float abs_tolerance) const {
+ return ApproximatelyEqual(transform, abs_tolerance, abs_tolerance, 0.0f);
+ }
+ // Checks approximate equality with default tolerances. Note that the
+ // tolerance for translation is big to tolerate scroll components due to
+ // snapping (floating point error might round the other way).
+ bool ApproximatelyEqual(const gfx::Transform& transform) const {
+ return ApproximatelyEqual(transform, 1.0f, 0.1f, 0.0f);
+ }
- // TODO(crbug.com/1167153) skia::Matrix44 is deprecated, this is to help in
- // moving the code base towards SkM44, although eventually this class should
- // just hold an SkM44
- SkM44 GetMatrixAsSkM44() const;
+ void EnsureFullMatrixForTesting() { EnsureFullMatrix(); }
- bool ApproximatelyEqual(const gfx::Transform& transform) const;
-
+ // Returns a string in the format of "[ row0\n, row1\n, row2\n, row3 ]\n".
std::string ToString() const;
+ // Returns a string containing decomposed components.
+ std::string ToDecomposedString() const;
+
private:
- void TransformPointInternal(const skia::Matrix44& xform, Point* point) const;
+ // Used internally to construct Transform with parameters in col-major order.
+ // clang-format off
+ constexpr Transform(double r0c0, double r1c0, double r2c0, double r3c0,
+ double r0c1, double r1c1, double r2c1, double r3c1,
+ double r0c2, double r1c2, double r2c2, double r3c2,
+ double r0c3, double r1c3, double r2c3, double r3c3)
+ : full_matrix_(true),
+ matrix_(r0c0, r1c0, r2c0, r3c0,
+ r0c1, r1c1, r2c1, r3c1,
+ r0c2, r1c2, r2c2, r3c2,
+ r0c3, r1c3, r2c3, r3c3) {}
+ // clang-format on
- void TransformPointInternal(const skia::Matrix44& xform, PointF* point) const;
+ constexpr Transform(float scale_x,
+ float scale_y,
+ float trans_x,
+ float trans_y)
+ : axis_2d_(AxisTransform2d::FromScaleAndTranslation(
+ Vector2dF(scale_x, scale_y),
+ Vector2dF(trans_x, trans_y))) {}
- void TransformPointInternal(const skia::Matrix44& xform,
- Point3F* point) const;
+ // Used internally to construct a Transform with uninitialized full matrix.
+ explicit Transform(Matrix44::UninitializedTag tag)
+ : full_matrix_(true), matrix_(tag) {}
- void TransformVectorInternal(const skia::Matrix44& xform,
- Vector3dF* vector) const;
+ PointF MapPointInternal(const Matrix44& matrix, const PointF& point) const;
+ Point3F MapPointInternal(const Matrix44& matrix, const Point3F& point) const;
- skia::Matrix44 matrix_;
+ Matrix44 GetFullMatrix() const;
+ Matrix44& EnsureFullMatrix();
- // copy/assign are allowed.
+ // axis_2d_ is used if full_matrix_ is false, otherwise matrix_ is used.
+ // See the class documentation for more details about how we use them.
+ bool full_matrix_ = false;
+ union {
+ // Each constructor must explicitly initialize one of the following,
+ // according to the value of full_matrix_.
+ AxisTransform2d axis_2d_;
+ Matrix44 matrix_;
+ };
};
// This is declared here for use in gtest-based unit tests but is defined in
diff --git a/ui/gfx/geometry/transform_operation.cc b/ui/gfx/geometry/transform_operation.cc
index 12303f5..c82d463 100644
--- a/ui/gfx/geometry/transform_operation.cc
+++ b/ui/gfx/geometry/transform_operation.cc
@@ -1,12 +1,13 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/gfx/geometry/transform_operation.h"
+
+#include <algorithm>
#include <limits>
#include <utility>
-#include "ui/gfx/geometry/transform_operation.h"
-
#include "base/check_op.h"
#include "base/notreached.h"
#include "base/numerics/math_constants.h"
@@ -24,6 +25,13 @@
namespace gfx {
bool TransformOperation::IsIdentity() const {
+ if (type == TRANSFORM_OPERATION_ROTATE) {
+ // We can't use matrix.IsIdentity() because rotate(n*360) is not identity,
+ // but the matrix is identity.
+ return rotate.angle == 0 ||
+ // Rotation with zero length axis is treated as identity.
+ (rotate.axis.x == 0 && rotate.axis.y == 0 && rotate.axis.z == 0);
+ }
return matrix.IsIdentity();
}
@@ -32,15 +40,18 @@
}
static bool ShareSameAxis(const TransformOperation* from,
+ bool is_identity_from,
const TransformOperation* to,
+ bool is_identity_to,
SkScalar* axis_x,
SkScalar* axis_y,
SkScalar* axis_z,
SkScalar* angle_from) {
- if (IsOperationIdentity(from) && IsOperationIdentity(to))
- return false;
+ DCHECK_EQ(is_identity_from, IsOperationIdentity(from));
+ DCHECK_EQ(is_identity_to, IsOperationIdentity(to));
+ DCHECK(!is_identity_from || !is_identity_to);
- if (IsOperationIdentity(from) && !IsOperationIdentity(to)) {
+ if (is_identity_from && !is_identity_to) {
*axis_x = to->rotate.axis.x;
*axis_y = to->rotate.axis.y;
*axis_z = to->rotate.axis.z;
@@ -48,7 +59,7 @@
return true;
}
- if (!IsOperationIdentity(from) && IsOperationIdentity(to)) {
+ if (!is_identity_from && is_identity_to) {
*axis_x = from->rotate.axis.x;
*axis_y = from->rotate.axis.y;
*axis_z = from->rotate.axis.z;
@@ -106,9 +117,12 @@
case TransformOperation::TRANSFORM_OPERATION_SKEW:
matrix.Skew(skew.x, skew.y);
break;
- case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
- matrix.ApplyPerspectiveDepth(perspective_depth);
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE: {
+ Transform m;
+ m.set_rc(3, 2, perspective_m43);
+ matrix.PreConcat(m);
break;
+ }
case TransformOperation::TRANSFORM_OPERATION_MATRIX:
case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
break;
@@ -147,18 +161,10 @@
return base::IsApproximatelyEqual(skew.x, other.skew.x, tolerance) &&
base::IsApproximatelyEqual(skew.y, other.skew.y, tolerance);
case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
- return base::IsApproximatelyEqual(perspective_depth,
- other.perspective_depth, tolerance);
+ return base::IsApproximatelyEqual(perspective_m43, other.perspective_m43,
+ tolerance);
case TransformOperation::TRANSFORM_OPERATION_MATRIX:
- // TODO(vollick): we could expose a tolerance on gfx::Transform, but it's
- // complex since we need a different tolerance per component. Driving this
- // with a single tolerance will take some care. For now, we will check
- // exact equality where the tolerance is 0.0f, otherwise we will use the
- // unparameterized version of gfx::Transform::ApproximatelyEqual.
- if (tolerance == 0.0f)
- return matrix == other.matrix;
- else
- return matrix.ApproximatelyEqual(other.matrix);
+ return matrix.ApproximatelyEqual(other.matrix, tolerance);
case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
return other.matrix.IsIdentity();
}
@@ -171,12 +177,14 @@
const TransformOperation* to,
SkScalar progress,
TransformOperation* result) {
- if (IsOperationIdentity(from) && IsOperationIdentity(to))
+ bool is_identity_from = IsOperationIdentity(from);
+ bool is_identity_to = IsOperationIdentity(to);
+ if (is_identity_from && is_identity_to)
return true;
TransformOperation::Type interpolation_type =
TransformOperation::TRANSFORM_OPERATION_IDENTITY;
- if (IsOperationIdentity(to))
+ if (is_identity_to)
interpolation_type = from->type;
else
interpolation_type = to->type;
@@ -184,12 +192,12 @@
switch (interpolation_type) {
case TransformOperation::TRANSFORM_OPERATION_TRANSLATE: {
- SkScalar from_x = IsOperationIdentity(from) ? 0 : from->translate.x;
- SkScalar from_y = IsOperationIdentity(from) ? 0 : from->translate.y;
- SkScalar from_z = IsOperationIdentity(from) ? 0 : from->translate.z;
- SkScalar to_x = IsOperationIdentity(to) ? 0 : to->translate.x;
- SkScalar to_y = IsOperationIdentity(to) ? 0 : to->translate.y;
- SkScalar to_z = IsOperationIdentity(to) ? 0 : to->translate.z;
+ SkScalar from_x = is_identity_from ? 0 : from->translate.x;
+ SkScalar from_y = is_identity_from ? 0 : from->translate.y;
+ SkScalar from_z = is_identity_from ? 0 : from->translate.z;
+ SkScalar to_x = is_identity_to ? 0 : to->translate.x;
+ SkScalar to_y = is_identity_to ? 0 : to->translate.y;
+ SkScalar to_z = is_identity_to ? 0 : to->translate.z;
result->translate.x = BlendSkScalars(from_x, to_x, progress),
result->translate.y = BlendSkScalars(from_y, to_y, progress),
result->translate.z = BlendSkScalars(from_z, to_z, progress),
@@ -201,18 +209,19 @@
SkScalar axis_y = 0;
SkScalar axis_z = 1;
SkScalar from_angle = 0;
- SkScalar to_angle = IsOperationIdentity(to) ? 0 : to->rotate.angle;
- if (ShareSameAxis(from, to, &axis_x, &axis_y, &axis_z, &from_angle)) {
+ SkScalar to_angle = is_identity_to ? 0 : to->rotate.angle;
+ if (ShareSameAxis(from, is_identity_from, to, is_identity_to, &axis_x,
+ &axis_y, &axis_z, &from_angle)) {
result->rotate.axis.x = axis_x;
result->rotate.axis.y = axis_y;
result->rotate.axis.z = axis_z;
result->rotate.angle = BlendSkScalars(from_angle, to_angle, progress);
result->Bake();
} else {
- if (!IsOperationIdentity(to))
+ if (!is_identity_to)
result->matrix = to->matrix;
gfx::Transform from_matrix;
- if (!IsOperationIdentity(from))
+ if (!is_identity_from)
from_matrix = from->matrix;
if (!result->matrix.Blend(from_matrix, progress))
return false;
@@ -220,12 +229,12 @@
break;
}
case TransformOperation::TRANSFORM_OPERATION_SCALE: {
- SkScalar from_x = IsOperationIdentity(from) ? 1 : from->scale.x;
- SkScalar from_y = IsOperationIdentity(from) ? 1 : from->scale.y;
- SkScalar from_z = IsOperationIdentity(from) ? 1 : from->scale.z;
- SkScalar to_x = IsOperationIdentity(to) ? 1 : to->scale.x;
- SkScalar to_y = IsOperationIdentity(to) ? 1 : to->scale.y;
- SkScalar to_z = IsOperationIdentity(to) ? 1 : to->scale.z;
+ SkScalar from_x = is_identity_from ? 1 : from->scale.x;
+ SkScalar from_y = is_identity_from ? 1 : from->scale.y;
+ SkScalar from_z = is_identity_from ? 1 : from->scale.z;
+ SkScalar to_x = is_identity_to ? 1 : to->scale.x;
+ SkScalar to_y = is_identity_to ? 1 : to->scale.y;
+ SkScalar to_z = is_identity_to ? 1 : to->scale.z;
result->scale.x = BlendSkScalars(from_x, to_x, progress);
result->scale.y = BlendSkScalars(from_y, to_y, progress);
result->scale.z = BlendSkScalars(from_z, to_z, progress);
@@ -235,40 +244,44 @@
case TransformOperation::TRANSFORM_OPERATION_SKEWX:
case TransformOperation::TRANSFORM_OPERATION_SKEWY:
case TransformOperation::TRANSFORM_OPERATION_SKEW: {
- SkScalar from_x = IsOperationIdentity(from) ? 0 : from->skew.x;
- SkScalar from_y = IsOperationIdentity(from) ? 0 : from->skew.y;
- SkScalar to_x = IsOperationIdentity(to) ? 0 : to->skew.x;
- SkScalar to_y = IsOperationIdentity(to) ? 0 : to->skew.y;
+ SkScalar from_x = is_identity_from ? 0 : from->skew.x;
+ SkScalar from_y = is_identity_from ? 0 : from->skew.y;
+ SkScalar to_x = is_identity_to ? 0 : to->skew.x;
+ SkScalar to_y = is_identity_to ? 0 : to->skew.y;
result->skew.x = BlendSkScalars(from_x, to_x, progress);
result->skew.y = BlendSkScalars(from_y, to_y, progress);
result->Bake();
break;
}
case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE: {
- SkScalar from_perspective_depth =
- IsOperationIdentity(from) ? std::numeric_limits<SkScalar>::max()
- : from->perspective_depth;
- SkScalar to_perspective_depth = IsOperationIdentity(to)
- ? std::numeric_limits<SkScalar>::max()
- : to->perspective_depth;
- if (from_perspective_depth == 0.f || to_perspective_depth == 0.f)
- return false;
+ SkScalar from_perspective_m43;
+ if (is_identity_from) {
+ from_perspective_m43 = 0.f;
+ } else {
+ DCHECK_LE(from->perspective_m43, 0.0f);
+ DCHECK_GE(from->perspective_m43, -1.0f);
+ from_perspective_m43 = from->perspective_m43;
+ }
+ SkScalar to_perspective_m43;
+ if (is_identity_to) {
+ to_perspective_m43 = 0.f;
+ } else {
+ DCHECK_LE(to->perspective_m43, 0.0f);
+ DCHECK_GE(to->perspective_m43, -1.0f);
+ to_perspective_m43 = to->perspective_m43;
+ }
- SkScalar blended_perspective_depth = BlendSkScalars(
- 1.f / from_perspective_depth, 1.f / to_perspective_depth, progress);
-
- if (blended_perspective_depth == 0.f)
- return false;
-
- result->perspective_depth = 1.f / blended_perspective_depth;
+ result->perspective_m43 = std::clamp(
+ BlendSkScalars(from_perspective_m43, to_perspective_m43, progress),
+ -1.0f, 0.0f);
result->Bake();
break;
}
case TransformOperation::TRANSFORM_OPERATION_MATRIX: {
- if (!IsOperationIdentity(to))
+ if (!is_identity_to)
result->matrix = to->matrix;
gfx::Transform from_matrix;
- if (!IsOperationIdentity(from))
+ if (!is_identity_from)
from_matrix = from->matrix;
if (!result->matrix.Blend(from_matrix, progress))
return false;
@@ -352,10 +365,8 @@
*box = gfx::BoxF();
- gfx::Point3F point_rotated_from = point;
- from_transform.TransformPoint(&point_rotated_from);
- gfx::Point3F point_rotated_to = point;
- to_transform.TransformPoint(&point_rotated_to);
+ gfx::Point3F point_rotated_from = from_transform.MapPoint(point);
+ gfx::Point3F point_rotated_to = to_transform.MapPoint(point);
box->set_origin(point_rotated_from);
box->ExpandTo(point_rotated_to);
@@ -371,7 +382,7 @@
&num_candidates);
} else {
gfx::Vector3dF normal = axis;
- normal.Scale(1.f / normal.Length());
+ normal.InvScale(normal.Length());
// First, find center of rotation.
gfx::Point3F origin;
@@ -386,7 +397,7 @@
if (v1_length == 0.f)
return;
- v1.Scale(1.f / v1_length);
+ v1.InvScale(v1_length);
gfx::Vector3dF v2 = gfx::CrossProduct(normal, v1);
// v1 is the basis vector in the direction of the point.
// i.e. with a rotation of 0, v1 is our +x vector.
@@ -427,8 +438,7 @@
gfx::Transform rotation;
rotation.RotateAbout(axis, gfx::RadToDeg(radians));
- gfx::Point3F rotated = point;
- rotation.TransformPoint(&rotated);
+ gfx::Point3F rotated = rotation.MapPoint(point);
box->ExpandTo(rotated);
}
@@ -470,11 +480,9 @@
!BlendTransformOperations(from, to, max_progress, &to_operation))
return false;
- *bounds = box;
- from_operation.matrix.TransformBox(bounds);
+ *bounds = from_operation.matrix.MapBox(box);
- gfx::BoxF to_box = box;
- to_operation.matrix.TransformBox(&to_box);
+ BoxF to_box = to_operation.matrix.MapBox(box);
bounds->ExpandTo(to_box);
return true;
@@ -484,8 +492,10 @@
SkScalar axis_y = 0;
SkScalar axis_z = 1;
SkScalar from_angle = 0;
- if (!ShareSameAxis(from, to, &axis_x, &axis_y, &axis_z, &from_angle))
+ if (!ShareSameAxis(from, is_identity_from, to, is_identity_to, &axis_x,
+ &axis_y, &axis_z, &from_angle)) {
return false;
+ }
bool first_point = true;
for (int i = 0; i < 8; ++i) {
diff --git a/ui/gfx/geometry/transform_operation.h b/ui/gfx/geometry/transform_operation.h
index 8026bdf..ffd53b1 100644
--- a/ui/gfx/geometry/transform_operation.h
+++ b/ui/gfx/geometry/transform_operation.h
@@ -1,10 +1,12 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_GEOMETRY_TRANSFORM_OPERATION_H_
#define UI_GFX_GEOMETRY_TRANSFORM_OPERATION_H_
+// TODO(crbug.com/1359528): Remove dependency to Skia.
+#include "third_party/skia/include/core/SkScalar.h"
#include "ui/gfx/geometry/geometry_skia_export.h"
#include "ui/gfx/geometry/transform.h"
@@ -28,7 +30,9 @@
gfx::Transform matrix;
union {
- SkScalar perspective_depth;
+ // We store the transform matrix component for perspective, which is
+ // -1/depth. This allows representing infinite distance correctly.
+ SkScalar perspective_m43;
struct {
SkScalar x, y;
diff --git a/ui/gfx/geometry/transform_operations.cc b/ui/gfx/geometry/transform_operations.cc
index 5d93258..f9c2ee1 100644
--- a/ui/gfx/geometry/transform_operations.cc
+++ b/ui/gfx/geometry/transform_operations.cc
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -37,7 +37,7 @@
Transform TransformOperations::ApplyRemaining(size_t start) const {
Transform to_return;
for (size_t i = start; i < operations_.size(); i++) {
- to_return.PreconcatTransform(operations_[i].matrix);
+ to_return.PreConcat(operations_[i].matrix);
}
return to_return;
}
@@ -286,10 +286,15 @@
decomposed_transforms_.clear();
}
-void TransformOperations::AppendPerspective(SkScalar depth) {
+void TransformOperations::AppendPerspective(absl::optional<SkScalar> depth) {
TransformOperation to_add;
to_add.type = TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE;
- to_add.perspective_depth = depth;
+ if (depth) {
+ DCHECK_GE(*depth, 1.0f);
+ to_add.perspective_m43 = -1.0f / *depth;
+ } else {
+ to_add.perspective_m43 = 0.0f;
+ }
to_add.Bake();
operations_.push_back(to_add);
decomposed_transforms_.clear();
@@ -362,7 +367,7 @@
DecomposedTransform matrix_transform = BlendDecomposedTransforms(
*decomposed_transforms_[matching_prefix_length].get(),
*from.decomposed_transforms_[matching_prefix_length].get(), progress);
- result->AppendMatrix(ComposeTransform(matrix_transform));
+ result->AppendMatrix(Transform::Compose(matrix_transform));
}
return true;
}
@@ -371,12 +376,13 @@
size_t start_offset) const {
auto it = decomposed_transforms_.find(start_offset);
if (it == decomposed_transforms_.end()) {
- std::unique_ptr<DecomposedTransform> decomposed_transform =
- std::make_unique<DecomposedTransform>();
Transform transform = ApplyRemaining(start_offset);
- if (!DecomposeTransform(decomposed_transform.get(), transform))
+ if (absl::optional<DecomposedTransform> decomp = transform.Decompose()) {
+ decomposed_transforms_[start_offset] =
+ std::make_unique<DecomposedTransform>(*decomp);
+ } else {
return false;
- decomposed_transforms_[start_offset] = std::move(decomposed_transform);
+ }
}
return true;
}
diff --git a/ui/gfx/geometry/transform_operations.h b/ui/gfx/geometry/transform_operations.h
index f1c9a89..1eaa0d7 100644
--- a/ui/gfx/geometry/transform_operations.h
+++ b/ui/gfx/geometry/transform_operations.h
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,6 +11,7 @@
#include "base/check_op.h"
#include "base/gtest_prod_util.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/geometry_skia_export.h"
#include "ui/gfx/geometry/transform.h"
#include "ui/gfx/geometry/transform_operation.h"
@@ -99,7 +100,7 @@
void AppendSkewX(SkScalar x);
void AppendSkewY(SkScalar y);
void AppendSkew(SkScalar x, SkScalar y);
- void AppendPerspective(SkScalar depth);
+ void AppendPerspective(absl::optional<SkScalar> depth);
void AppendMatrix(const Transform& matrix);
void AppendIdentity();
void Append(const TransformOperation& operation);
diff --git a/ui/gfx/geometry/transform_operations_unittest.cc b/ui/gfx/geometry/transform_operations_unittest.cc
index 75f9144..556b8d2 100644
--- a/ui/gfx/geometry/transform_operations_unittest.cc
+++ b/ui/gfx/geometry/transform_operations_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -15,7 +15,7 @@
#include "ui/gfx/animation/tween.h"
#include "ui/gfx/geometry/box_f.h"
#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/geometry/test/transform_test_util.h"
+#include "ui/gfx/geometry/test/geometry_util.h"
#include "ui/gfx/geometry/vector3d_f.h"
namespace gfx {
@@ -24,7 +24,7 @@
void ExpectTransformOperationEqual(const TransformOperation& lhs,
const TransformOperation& rhs) {
EXPECT_EQ(lhs.type, rhs.type);
- ExpectTransformationMatrixEq(lhs.matrix, rhs.matrix);
+ EXPECT_TRANSFORM_EQ(lhs.matrix, rhs.matrix);
switch (lhs.type) {
case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
EXPECT_FLOAT_EQ(lhs.translate.x, rhs.translate.x);
@@ -49,7 +49,7 @@
EXPECT_FLOAT_EQ(lhs.skew.y, rhs.skew.y);
break;
case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
- EXPECT_FLOAT_EQ(lhs.perspective_depth, rhs.perspective_depth);
+ EXPECT_FLOAT_EQ(lhs.perspective_m43, rhs.perspective_m43);
break;
case TransformOperation::TRANSFORM_OPERATION_MATRIX:
case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
@@ -236,7 +236,7 @@
operations.AppendTranslate(x, y, z);
gfx::Transform expected;
expected.Translate3d(x, y, z);
- ExpectTransformationMatrixEq(expected, operations.Apply());
+ EXPECT_TRANSFORM_EQ(expected, operations.Apply());
}
TEST(TransformOperationTest, ApplyRotate) {
@@ -248,7 +248,7 @@
operations.AppendRotate(x, y, z, degrees);
gfx::Transform expected;
expected.RotateAbout(gfx::Vector3dF(x, y, z), degrees);
- ExpectTransformationMatrixEq(expected, operations.Apply());
+ EXPECT_TRANSFORM_EQ(expected, operations.Apply());
}
TEST(TransformOperationTest, ApplyScale) {
@@ -259,7 +259,7 @@
operations.AppendScale(x, y, z);
gfx::Transform expected;
expected.Scale3d(x, y, z);
- ExpectTransformationMatrixEq(expected, operations.Apply());
+ EXPECT_TRANSFORM_EQ(expected, operations.Apply());
}
TEST(TransformOperationTest, ApplySkew) {
@@ -269,7 +269,7 @@
operations.AppendSkew(x, y);
gfx::Transform expected;
expected.Skew(x, y);
- ExpectTransformationMatrixEq(expected, operations.Apply());
+ EXPECT_TRANSFORM_EQ(expected, operations.Apply());
}
TEST(TransformOperationTest, ApplyPerspective) {
@@ -278,7 +278,7 @@
operations.AppendPerspective(depth);
gfx::Transform expected;
expected.ApplyPerspectiveDepth(depth);
- ExpectTransformationMatrixEq(expected, operations.Apply());
+ EXPECT_TRANSFORM_EQ(expected, operations.Apply());
}
TEST(TransformOperationTest, ApplyMatrix) {
@@ -289,7 +289,7 @@
expected_matrix.Translate3d(dx, dy, dz);
TransformOperations matrix_transform;
matrix_transform.AppendMatrix(expected_matrix);
- ExpectTransformationMatrixEq(expected_matrix, matrix_transform.Apply());
+ EXPECT_TRANSFORM_EQ(expected_matrix, matrix_transform.Apply());
}
TEST(TransformOperationTest, ApplyOrder) {
@@ -312,9 +312,9 @@
expected_translate_matrix.Translate3d(dx, dy, dz);
gfx::Transform expected_combined_matrix = expected_scale_matrix;
- expected_combined_matrix.PreconcatTransform(expected_translate_matrix);
+ expected_combined_matrix.PreConcat(expected_translate_matrix);
- ExpectTransformationMatrixEq(expected_combined_matrix, operations.Apply());
+ EXPECT_TRANSFORM_EQ(expected_combined_matrix, operations.Apply());
}
TEST(TransformOperationTest, BlendOrder) {
@@ -376,12 +376,12 @@
blended_translate.Blend(translate_from, progress);
gfx::Transform expected = blended_scale;
- expected.PreconcatTransform(blended_translate);
+ expected.PreConcat(blended_translate);
TransformOperations blended = operations_to.Blend(operations_from, progress);
- ExpectTransformationMatrixEq(expected, blended.Apply());
- ExpectTransformationMatrixEq(operations_expected.Apply(), blended.Apply());
+ EXPECT_TRANSFORM_EQ(expected, blended.Apply());
+ EXPECT_TRANSFORM_EQ(operations_expected.Apply(), blended.Apply());
EXPECT_EQ(operations_expected.size(), blended.size());
for (size_t i = 0; i < operations_expected.size(); ++i) {
TransformOperation expected_op = operations_expected.at(i);
@@ -401,7 +401,7 @@
gfx::Transform blended_append_scale = appended_scale;
blended_append_scale.Blend(gfx::Transform(), progress);
- expected.PreconcatTransform(blended_append_scale);
+ expected.PreConcat(blended_append_scale);
operations_expected.AppendScale(
gfx::Tween::FloatValueBetween(progress, 1, sx3),
@@ -410,8 +410,8 @@
blended = operations_to.Blend(operations_from, progress);
- ExpectTransformationMatrixEq(expected, blended.Apply());
- ExpectTransformationMatrixEq(operations_expected.Apply(), blended.Apply());
+ EXPECT_TRANSFORM_EQ(expected, blended.Apply());
+ EXPECT_TRANSFORM_EQ(operations_expected.Apply(), blended.Apply());
EXPECT_EQ(operations_expected.size(), blended.size());
for (size_t i = 0; i < operations_expected.size(); ++i) {
TransformOperation expected_op = operations_expected.at(i);
@@ -433,14 +433,14 @@
blended_matrix.Blend(transform_from, progress);
expected = blended_scale;
- expected.PreconcatTransform(blended_translate);
- expected.PreconcatTransform(blended_matrix);
+ expected.PreConcat(blended_translate);
+ expected.PreConcat(blended_matrix);
operations_expected = base_operations_expected;
operations_expected.AppendMatrix(blended_matrix);
- ExpectTransformationMatrixEq(expected, blended.Apply());
- ExpectTransformationMatrixEq(operations_expected.Apply(), blended.Apply());
+ EXPECT_TRANSFORM_EQ(expected, blended.Apply());
+ EXPECT_TRANSFORM_EQ(operations_expected.Apply(), blended.Apply());
EXPECT_EQ(operations_expected.size(), blended.size());
for (size_t i = 0; i < operations_expected.size(); ++i) {
TransformOperation expected_op = operations_expected.at(i);
@@ -457,8 +457,8 @@
const TransformOperations& to_transform) {
gfx::Transform expected_matrix = to_matrix;
expected_matrix.Blend(from_matrix, progress);
- ExpectTransformationMatrixEq(
- expected_matrix, to_transform.Blend(from_transform, progress).Apply());
+ EXPECT_TRANSFORM_EQ(expected_matrix,
+ to_transform.Blend(from_transform, progress).Apply());
}
TEST(TransformOperationTest, BlendProgress) {
@@ -526,8 +526,8 @@
gfx::Transform expected = to;
expected.Blend(from, progress);
- ExpectTransformationMatrixEq(
- expected, operations_to.Blend(operations_from, progress).Apply());
+ EXPECT_TRANSFORM_EQ(expected,
+ operations_to.Blend(operations_from, progress).Apply());
}
TEST(TransformOperationTest, LargeRotationsWithSameAxis) {
@@ -542,8 +542,8 @@
gfx::Transform expected;
expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 180);
- ExpectTransformationMatrixEq(
- expected, operations_to.Blend(operations_from, progress).Apply());
+ EXPECT_TRANSFORM_EQ(expected,
+ operations_to.Blend(operations_from, progress).Apply());
}
TEST(TransformOperationTest, LargeRotationsWithSameAxisInDifferentDirection) {
@@ -557,8 +557,8 @@
gfx::Transform expected;
- ExpectTransformationMatrixEq(
- expected, operations_to.Blend(operations_from, progress).Apply());
+ EXPECT_TRANSFORM_EQ(expected,
+ operations_to.Blend(operations_from, progress).Apply());
}
TEST(TransformOperationTest, LargeRotationsWithDifferentAxes) {
@@ -578,8 +578,8 @@
gfx::Transform expected = matrix_to;
expected.Blend(matrix_from, progress);
- ExpectTransformationMatrixEq(
- expected, operations_to.Blend(operations_from, progress).Apply());
+ EXPECT_TRANSFORM_EQ(expected,
+ operations_to.Blend(operations_from, progress).Apply());
}
TEST(TransformOperationTest, RotationFromZeroDegDifferentAxes) {
@@ -592,8 +592,8 @@
SkScalar progress = 0.5f;
gfx::Transform expected;
expected.RotateAbout(gfx::Vector3dF(0, 1, 0), 225);
- ExpectTransformationMatrixEq(
- expected, operations_to.Blend(operations_from, progress).Apply());
+ EXPECT_TRANSFORM_EQ(expected,
+ operations_to.Blend(operations_from, progress).Apply());
}
TEST(TransformOperationTest, RotationFromZeroDegSameAxes) {
@@ -606,8 +606,8 @@
SkScalar progress = 0.5f;
gfx::Transform expected;
expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 225);
- ExpectTransformationMatrixEq(
- expected, operations_to.Blend(operations_from, progress).Apply());
+ EXPECT_TRANSFORM_EQ(expected,
+ operations_to.Blend(operations_from, progress).Apply());
}
TEST(TransformOperationTest, RotationToZeroDegDifferentAxes) {
@@ -620,8 +620,8 @@
SkScalar progress = 0.5f;
gfx::Transform expected;
expected.RotateAbout(gfx::Vector3dF(0, 1, 0), 225);
- ExpectTransformationMatrixEq(
- expected, operations_to.Blend(operations_from, progress).Apply());
+ EXPECT_TRANSFORM_EQ(expected,
+ operations_to.Blend(operations_from, progress).Apply());
}
TEST(TransformOperationTest, RotationToZeroDegSameAxes) {
@@ -634,8 +634,8 @@
SkScalar progress = 0.5f;
gfx::Transform expected;
expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 225);
- ExpectTransformationMatrixEq(
- expected, operations_to.Blend(operations_from, progress).Apply());
+ EXPECT_TRANSFORM_EQ(expected,
+ operations_to.Blend(operations_from, progress).Apply());
}
TEST(TransformOperationTest, BlendRotationFromIdentity) {
@@ -651,7 +651,7 @@
gfx::Transform expected;
expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 45);
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
expected, operations.Blend(*identity_operation, progress).Apply());
progress = -0.5f;
@@ -659,7 +659,7 @@
expected.MakeIdentity();
expected.RotateAbout(gfx::Vector3dF(0, 0, 1), -45);
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
expected, operations.Blend(*identity_operation, progress).Apply());
progress = 1.5f;
@@ -667,7 +667,7 @@
expected.MakeIdentity();
expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 135);
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
expected, operations.Blend(*identity_operation, progress).Apply());
}
}
@@ -685,7 +685,7 @@
gfx::Transform expected;
expected.Translate3d(1, 1, 1);
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
expected, operations.Blend(*identity_operation, progress).Apply());
progress = -0.5f;
@@ -693,7 +693,7 @@
expected.MakeIdentity();
expected.Translate3d(-1, -1, -1);
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
expected, operations.Blend(*identity_operation, progress).Apply());
progress = 1.5f;
@@ -701,7 +701,7 @@
expected.MakeIdentity();
expected.Translate3d(3, 3, 3);
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
expected, operations.Blend(*identity_operation, progress).Apply());
}
}
@@ -719,7 +719,7 @@
gfx::Transform expected;
expected.Scale3d(2, 2, 2);
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
expected, operations.Blend(*identity_operation, progress).Apply());
progress = -0.5f;
@@ -727,7 +727,7 @@
expected.MakeIdentity();
expected.Scale3d(0, 0, 0);
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
expected, operations.Blend(*identity_operation, progress).Apply());
progress = 1.5f;
@@ -735,7 +735,7 @@
expected.MakeIdentity();
expected.Scale3d(4, 4, 4);
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
expected, operations.Blend(*identity_operation, progress).Apply());
}
}
@@ -751,24 +751,24 @@
gfx::Transform expected;
expected.Skew(1, 1);
- ExpectTransformationMatrixEq(
- expected, operations.Blend(empty_operation, progress).Apply());
+ EXPECT_TRANSFORM_EQ(expected,
+ operations.Blend(empty_operation, progress).Apply());
progress = -0.5f;
expected.MakeIdentity();
expected.Skew(-1, -1);
- ExpectTransformationMatrixEq(
- expected, operations.Blend(empty_operation, progress).Apply());
+ EXPECT_TRANSFORM_EQ(expected,
+ operations.Blend(empty_operation, progress).Apply());
progress = 1.5f;
expected.MakeIdentity();
expected.Skew(3, 3);
- ExpectTransformationMatrixEq(
- expected, operations.Blend(empty_operation, progress).Apply());
+ EXPECT_TRANSFORM_EQ(expected,
+ operations.Blend(empty_operation, progress).Apply());
}
TEST(TransformOperationTest, BlendPerspectiveFromIdentity) {
@@ -784,7 +784,7 @@
gfx::Transform expected;
expected.ApplyPerspectiveDepth(2000);
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
expected, operations.Blend(*identity_operation, progress).Apply());
}
}
@@ -802,7 +802,7 @@
gfx::Transform expected;
expected.RotateAbout(gfx::Vector3dF(0, 0, 1), 45);
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
expected, identity_operation->Blend(operations, progress).Apply());
}
}
@@ -820,7 +820,7 @@
gfx::Transform expected;
expected.Translate3d(1, 1, 1);
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
expected, identity_operation->Blend(operations, progress).Apply());
}
}
@@ -838,7 +838,7 @@
gfx::Transform expected;
expected.Scale3d(2, 2, 2);
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
expected, identity_operation->Blend(operations, progress).Apply());
}
}
@@ -854,8 +854,8 @@
gfx::Transform expected;
expected.Skew(1, 1);
- ExpectTransformationMatrixEq(
- expected, empty_operation.Blend(operations, progress).Apply());
+ EXPECT_TRANSFORM_EQ(expected,
+ empty_operation.Blend(operations, progress).Apply());
}
TEST(TransformOperationTest, BlendPerspectiveToIdentity) {
@@ -871,7 +871,7 @@
gfx::Transform expected;
expected.ApplyPerspectiveDepth(2000);
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
expected, identity_operation->Blend(operations, progress).Apply());
}
}
@@ -886,14 +886,12 @@
gfx::Transform expected;
expected.ApplyPerspectiveDepth(400);
- ExpectTransformationMatrixEq(expected,
- operations1.Blend(operations2, -0.5).Apply());
+ EXPECT_TRANSFORM_EQ(expected, operations1.Blend(operations2, -0.5).Apply());
expected.MakeIdentity();
expected.ApplyPerspectiveDepth(2000);
- ExpectTransformationMatrixEq(expected,
- operations1.Blend(operations2, 1.5).Apply());
+ EXPECT_TRANSFORM_EQ(expected, operations1.Blend(operations2, 1.5).Apply());
}
TEST(TransformOperationTest, ExtrapolateMatrixBlending) {
@@ -908,17 +906,15 @@
operations2.AppendMatrix(transform2);
gfx::Transform expected;
- ExpectTransformationMatrixEq(expected,
- operations1.Blend(operations2, 1.5).Apply());
+ EXPECT_TRANSFORM_EQ(expected, operations1.Blend(operations2, 1.5).Apply());
expected.Translate3d(4, 4, 4);
- ExpectTransformationMatrixEq(expected,
- operations1.Blend(operations2, -0.5).Apply());
+ EXPECT_TRANSFORM_EQ(expected, operations1.Blend(operations2, -0.5).Apply());
}
TEST(TransformOperationTest, NonDecomposableBlend) {
TransformOperations non_decomposible_transform;
- gfx::Transform non_decomposible_matrix(0, 0, 0, 0, 0, 0);
+ auto non_decomposible_matrix = gfx::Transform::MakeScale(0);
non_decomposible_transform.AppendMatrix(non_decomposible_matrix);
TransformOperations identity_transform;
@@ -926,18 +922,18 @@
identity_transform.AppendMatrix(identity_matrix);
// Before the half-way point, we should return the 'from' matrix.
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
non_decomposible_matrix,
identity_transform.Blend(non_decomposible_transform, 0.0f).Apply());
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
non_decomposible_matrix,
identity_transform.Blend(non_decomposible_transform, 0.49f).Apply());
// After the half-way point, we should return the 'to' matrix.
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
identity_matrix,
identity_transform.Blend(non_decomposible_transform, 0.5f).Apply());
- ExpectTransformationMatrixEq(
+ EXPECT_TRANSFORM_EQ(
identity_matrix,
identity_transform.Blend(non_decomposible_transform, 1.0f).Apply());
}
@@ -1227,8 +1223,7 @@
float t = step / (kNumSteps - 1.f);
t = gfx::Tween::FloatValueBetween(t, min_progress, max_progress);
gfx::Transform partial_transform = to.Blend(from, t).Apply();
- gfx::BoxF transformed = box;
- partial_transform.TransformBox(&transformed);
+ gfx::BoxF transformed = partial_transform.MapBox(box);
if (first_time) {
empirical_bounds = transformed;
@@ -1344,7 +1339,7 @@
gfx::Transform blended_transform =
to_operations.Blend(from_operations, progress).Apply();
- ExpectTransformationMatrixEq(blended_matrix, blended_transform);
+ EXPECT_TRANSFORM_EQ(blended_matrix, blended_transform);
}
}
@@ -1429,7 +1424,7 @@
gfx::Transform blended_transform =
operations_to.Blend(operations_from, max_progress).Apply();
gfx::Point3F blended_point(0.9f, 0.9f, 0.0f);
- blended_transform.TransformPoint(&blended_point);
+ blended_point = blended_transform.MapPoint(blended_point);
gfx::BoxF expanded_bounds = bounds;
expanded_bounds.ExpandTo(blended_point);
EXPECT_EQ(bounds.ToString(), expanded_bounds.ToString());
@@ -1715,9 +1710,9 @@
EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
lhs = rhs;
- lhs.at(6).perspective_depth += noise;
+ lhs.at(6).perspective_m43 += noise;
EXPECT_TRUE(lhs.ApproximatelyEqual(rhs, tolerance));
- lhs.at(6).perspective_depth = 801;
+ lhs.at(6).perspective_m43 = -1.0f / 810;
EXPECT_FALSE(lhs.ApproximatelyEqual(rhs, tolerance));
}
@@ -1810,4 +1805,11 @@
ExpectTransformOperationEqual(blended_ops.at(1), expected_ops.at(1));
}
+TEST(TransformOperationsTest, Rotate360IsNotIdentityOperation) {
+ TransformOperations operations;
+ operations.AppendRotate(0, 0, 2, 360);
+ EXPECT_FALSE(operations.IsIdentity());
+ EXPECT_TRUE(operations.Apply().IsIdentity());
+}
+
} // namespace gfx
diff --git a/ui/gfx/geometry/transform_unittest.cc b/ui/gfx/geometry/transform_unittest.cc
index 127c203..214ca28 100644
--- a/ui/gfx/geometry/transform_unittest.cc
+++ b/ui/gfx/geometry/transform_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -12,173 +12,334 @@
#include "base/cxx17_backports.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/geometry/angle_conversions.h"
+#include "ui/gfx/geometry/axis_transform2d.h"
#include "ui/gfx/geometry/box_f.h"
+#include "ui/gfx/geometry/decomposed_transform.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point3_f.h"
#include "ui/gfx/geometry/quad_f.h"
-#include "ui/gfx/geometry/rrect_f.h"
-#include "ui/gfx/geometry/transform_util.h"
+#include "ui/gfx/geometry/test/geometry_util.h"
#include "ui/gfx/geometry/vector3d_f.h"
namespace gfx {
namespace {
-#define EXPECT_ROW1_EQ(a, b, c, d, transform) \
- EXPECT_FLOAT_EQ((a), (transform).matrix().get(0, 0)); \
- EXPECT_FLOAT_EQ((b), (transform).matrix().get(0, 1)); \
- EXPECT_FLOAT_EQ((c), (transform).matrix().get(0, 2)); \
- EXPECT_FLOAT_EQ((d), (transform).matrix().get(0, 3));
+#define STATIC_ROW0_EQ(a, b, c, d, transform) \
+ static_assert((a) == (transform).rc(0, 0)); \
+ static_assert((b) == (transform).rc(0, 1)); \
+ static_assert((c) == (transform).rc(0, 2)); \
+ static_assert((d) == (transform).rc(0, 3));
-#define EXPECT_ROW2_EQ(a, b, c, d, transform) \
- EXPECT_FLOAT_EQ((a), (transform).matrix().get(1, 0)); \
- EXPECT_FLOAT_EQ((b), (transform).matrix().get(1, 1)); \
- EXPECT_FLOAT_EQ((c), (transform).matrix().get(1, 2)); \
- EXPECT_FLOAT_EQ((d), (transform).matrix().get(1, 3));
+#define STATIC_ROW1_EQ(a, b, c, d, transform) \
+ static_assert((a) == (transform).rc(1, 0)); \
+ static_assert((b) == (transform).rc(1, 1)); \
+ static_assert((c) == (transform).rc(1, 2)); \
+ static_assert((d) == (transform).rc(1, 3));
-#define EXPECT_ROW3_EQ(a, b, c, d, transform) \
- EXPECT_FLOAT_EQ((a), (transform).matrix().get(2, 0)); \
- EXPECT_FLOAT_EQ((b), (transform).matrix().get(2, 1)); \
- EXPECT_FLOAT_EQ((c), (transform).matrix().get(2, 2)); \
- EXPECT_FLOAT_EQ((d), (transform).matrix().get(2, 3));
+#define STATIC_ROW2_EQ(a, b, c, d, transform) \
+ static_assert((a) == (transform).rc(2, 0)); \
+ static_assert((b) == (transform).rc(2, 1)); \
+ static_assert((c) == (transform).rc(2, 2)); \
+ static_assert((d) == (transform).rc(2, 3));
-#define EXPECT_ROW4_EQ(a, b, c, d, transform) \
- EXPECT_FLOAT_EQ((a), (transform).matrix().get(3, 0)); \
- EXPECT_FLOAT_EQ((b), (transform).matrix().get(3, 1)); \
- EXPECT_FLOAT_EQ((c), (transform).matrix().get(3, 2)); \
- EXPECT_FLOAT_EQ((d), (transform).matrix().get(3, 3));
+#define STATIC_ROW3_EQ(a, b, c, d, transform) \
+ static_assert((a) == (transform).rc(3, 0)); \
+ static_assert((b) == (transform).rc(3, 1)); \
+ static_assert((c) == (transform).rc(3, 2)); \
+ static_assert((d) == (transform).rc(3, 3));
+
+#define EXPECT_ROW0_EQ(a, b, c, d, transform) \
+ EXPECT_FLOAT_EQ((a), (transform).rc(0, 0)); \
+ EXPECT_FLOAT_EQ((b), (transform).rc(0, 1)); \
+ EXPECT_FLOAT_EQ((c), (transform).rc(0, 2)); \
+ EXPECT_FLOAT_EQ((d), (transform).rc(0, 3));
+
+#define EXPECT_ROW1_EQ(a, b, c, d, transform) \
+ EXPECT_FLOAT_EQ((a), (transform).rc(1, 0)); \
+ EXPECT_FLOAT_EQ((b), (transform).rc(1, 1)); \
+ EXPECT_FLOAT_EQ((c), (transform).rc(1, 2)); \
+ EXPECT_FLOAT_EQ((d), (transform).rc(1, 3));
+
+#define EXPECT_ROW2_EQ(a, b, c, d, transform) \
+ EXPECT_FLOAT_EQ((a), (transform).rc(2, 0)); \
+ EXPECT_FLOAT_EQ((b), (transform).rc(2, 1)); \
+ EXPECT_FLOAT_EQ((c), (transform).rc(2, 2)); \
+ EXPECT_FLOAT_EQ((d), (transform).rc(2, 3));
+
+#define EXPECT_ROW3_EQ(a, b, c, d, transform) \
+ EXPECT_FLOAT_EQ((a), (transform).rc(3, 0)); \
+ EXPECT_FLOAT_EQ((b), (transform).rc(3, 1)); \
+ EXPECT_FLOAT_EQ((c), (transform).rc(3, 2)); \
+ EXPECT_FLOAT_EQ((d), (transform).rc(3, 3));
// Checking float values for equality close to zero is not robust using
// EXPECT_FLOAT_EQ (see gtest documentation). So, to verify rotation matrices,
// we must use a looser absolute error threshold in some places.
-#define EXPECT_ROW1_NEAR(a, b, c, d, transform, errorThreshold) \
- EXPECT_NEAR((a), (transform).matrix().get(0, 0), (errorThreshold)); \
- EXPECT_NEAR((b), (transform).matrix().get(0, 1), (errorThreshold)); \
- EXPECT_NEAR((c), (transform).matrix().get(0, 2), (errorThreshold)); \
- EXPECT_NEAR((d), (transform).matrix().get(0, 3), (errorThreshold));
+#define EXPECT_ROW0_NEAR(a, b, c, d, transform, errorThreshold) \
+ EXPECT_NEAR((a), (transform).rc(0, 0), (errorThreshold)); \
+ EXPECT_NEAR((b), (transform).rc(0, 1), (errorThreshold)); \
+ EXPECT_NEAR((c), (transform).rc(0, 2), (errorThreshold)); \
+ EXPECT_NEAR((d), (transform).rc(0, 3), (errorThreshold));
-#define EXPECT_ROW2_NEAR(a, b, c, d, transform, errorThreshold) \
- EXPECT_NEAR((a), (transform).matrix().get(1, 0), (errorThreshold)); \
- EXPECT_NEAR((b), (transform).matrix().get(1, 1), (errorThreshold)); \
- EXPECT_NEAR((c), (transform).matrix().get(1, 2), (errorThreshold)); \
- EXPECT_NEAR((d), (transform).matrix().get(1, 3), (errorThreshold));
+#define EXPECT_ROW1_NEAR(a, b, c, d, transform, errorThreshold) \
+ EXPECT_NEAR((a), (transform).rc(1, 0), (errorThreshold)); \
+ EXPECT_NEAR((b), (transform).rc(1, 1), (errorThreshold)); \
+ EXPECT_NEAR((c), (transform).rc(1, 2), (errorThreshold)); \
+ EXPECT_NEAR((d), (transform).rc(1, 3), (errorThreshold));
-#define EXPECT_ROW3_NEAR(a, b, c, d, transform, errorThreshold) \
- EXPECT_NEAR((a), (transform).matrix().get(2, 0), (errorThreshold)); \
- EXPECT_NEAR((b), (transform).matrix().get(2, 1), (errorThreshold)); \
- EXPECT_NEAR((c), (transform).matrix().get(2, 2), (errorThreshold)); \
- EXPECT_NEAR((d), (transform).matrix().get(2, 3), (errorThreshold));
+#define EXPECT_ROW2_NEAR(a, b, c, d, transform, errorThreshold) \
+ EXPECT_NEAR((a), (transform).rc(2, 0), (errorThreshold)); \
+ EXPECT_NEAR((b), (transform).rc(2, 1), (errorThreshold)); \
+ EXPECT_NEAR((c), (transform).rc(2, 2), (errorThreshold)); \
+ EXPECT_NEAR((d), (transform).rc(2, 3), (errorThreshold));
+
+bool PointsAreNearlyEqual(const PointF& lhs, const PointF& rhs) {
+ return lhs.IsWithinDistance(rhs, 0.01f);
+}
bool PointsAreNearlyEqual(const Point3F& lhs, const Point3F& rhs) {
- float epsilon = 0.0001f;
- return lhs.SquaredDistanceTo(rhs) < epsilon;
+ return lhs.SquaredDistanceTo(rhs) < 0.0001f;
}
bool MatricesAreNearlyEqual(const Transform& lhs, const Transform& rhs) {
float epsilon = 0.0001f;
for (int row = 0; row < 4; ++row) {
for (int col = 0; col < 4; ++col) {
- if (std::abs(lhs.matrix().get(row, col) - rhs.matrix().get(row, col)) >
- epsilon)
+ if (std::abs(lhs.rc(row, col) - rhs.rc(row, col)) > epsilon)
return false;
}
}
return true;
}
-void InitializeTestMatrix(Transform* transform) {
- skia::Matrix44& matrix = transform->matrix();
- matrix.set(0, 0, 10.f);
- matrix.set(1, 0, 11.f);
- matrix.set(2, 0, 12.f);
- matrix.set(3, 0, 13.f);
- matrix.set(0, 1, 14.f);
- matrix.set(1, 1, 15.f);
- matrix.set(2, 1, 16.f);
- matrix.set(3, 1, 17.f);
- matrix.set(0, 2, 18.f);
- matrix.set(1, 2, 19.f);
- matrix.set(2, 2, 20.f);
- matrix.set(3, 2, 21.f);
- matrix.set(0, 3, 22.f);
- matrix.set(1, 3, 23.f);
- matrix.set(2, 3, 24.f);
- matrix.set(3, 3, 25.f);
+Transform GetTestMatrix1() {
+ // clang-format off
+ constexpr Transform transform = Transform::ColMajor(10.0, 11.0, 12.0, 13.0,
+ 14.0, 15.0, 16.0, 17.0,
+ 18.0, 19.0, 20.0, 21.0,
+ 22.0, 23.0, 24.0, 25.0);
+ // clang-format on
- // Sanity check
- EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, (*transform));
- EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, (*transform));
- EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, (*transform));
- EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, (*transform));
+ STATIC_ROW0_EQ(10.0, 14.0, 18.0, 22.0, transform);
+ STATIC_ROW1_EQ(11.0, 15.0, 19.0, 23.0, transform);
+ STATIC_ROW2_EQ(12.0, 16.0, 20.0, 24.0, transform);
+ STATIC_ROW3_EQ(13.0, 17.0, 21.0, 25.0, transform);
+
+ EXPECT_ROW0_EQ(10.0, 14.0, 18.0, 22.0, transform);
+ EXPECT_ROW1_EQ(11.0, 15.0, 19.0, 23.0, transform);
+ EXPECT_ROW2_EQ(12.0, 16.0, 20.0, 24.0, transform);
+ EXPECT_ROW3_EQ(13.0, 17.0, 21.0, 25.0, transform);
+ return transform;
}
-void InitializeTestMatrix2(Transform* transform) {
- skia::Matrix44& matrix = transform->matrix();
- matrix.set(0, 0, 30.f);
- matrix.set(1, 0, 31.f);
- matrix.set(2, 0, 32.f);
- matrix.set(3, 0, 33.f);
- matrix.set(0, 1, 34.f);
- matrix.set(1, 1, 35.f);
- matrix.set(2, 1, 36.f);
- matrix.set(3, 1, 37.f);
- matrix.set(0, 2, 38.f);
- matrix.set(1, 2, 39.f);
- matrix.set(2, 2, 40.f);
- matrix.set(3, 2, 41.f);
- matrix.set(0, 3, 42.f);
- matrix.set(1, 3, 43.f);
- matrix.set(2, 3, 44.f);
- matrix.set(3, 3, 45.f);
+Transform GetTestMatrix2() {
+ constexpr Transform transform =
+ Transform::RowMajor(30.0, 34.0, 38.0, 42.0, 31.0, 35.0, 39.0, 43.0, 32.0,
+ 36.0, 40.0, 44.0, 33.0, 37.0, 41.0, 45.0);
+ // clang-format on
- // Sanity check
- EXPECT_ROW1_EQ(30.0f, 34.0f, 38.0f, 42.0f, (*transform));
- EXPECT_ROW2_EQ(31.0f, 35.0f, 39.0f, 43.0f, (*transform));
- EXPECT_ROW3_EQ(32.0f, 36.0f, 40.0f, 44.0f, (*transform));
- EXPECT_ROW4_EQ(33.0f, 37.0f, 41.0f, 45.0f, (*transform));
+ STATIC_ROW0_EQ(30.0, 34.0, 38.0, 42.0, transform);
+ STATIC_ROW1_EQ(31.0, 35.0, 39.0, 43.0, transform);
+ STATIC_ROW2_EQ(32.0, 36.0, 40.0, 44.0, transform);
+ STATIC_ROW3_EQ(33.0, 37.0, 41.0, 45.0, transform);
+
+ EXPECT_ROW0_EQ(30.0, 34.0, 38.0, 42.0, transform);
+ EXPECT_ROW1_EQ(31.0, 35.0, 39.0, 43.0, transform);
+ EXPECT_ROW2_EQ(32.0, 36.0, 40.0, 44.0, transform);
+ EXPECT_ROW3_EQ(33.0, 37.0, 41.0, 45.0, transform);
+ return transform;
}
-const SkScalar kApproxZero = std::numeric_limits<float>::epsilon();
-const SkScalar kApproxOne = 1 - kApproxZero;
-
-void InitializeApproxIdentityMatrix(Transform* transform) {
- skia::Matrix44& matrix = transform->matrix();
- matrix.set(0, 0, kApproxOne);
- matrix.set(0, 1, kApproxZero);
- matrix.set(0, 2, kApproxZero);
- matrix.set(0, 3, kApproxZero);
-
- matrix.set(1, 0, kApproxZero);
- matrix.set(1, 1, kApproxOne);
- matrix.set(1, 2, kApproxZero);
- matrix.set(1, 3, kApproxZero);
-
- matrix.set(2, 0, kApproxZero);
- matrix.set(2, 1, kApproxZero);
- matrix.set(2, 2, kApproxOne);
- matrix.set(2, 3, kApproxZero);
-
- matrix.set(3, 0, kApproxZero);
- matrix.set(3, 1, kApproxZero);
- matrix.set(3, 2, kApproxZero);
- matrix.set(3, 3, kApproxOne);
+Transform ApproxIdentityMatrix(double error) {
+ return Transform::ColMajor(1.0 - error, error, error, error, // col0
+ error, 1.0 - error, error, error, // col1
+ error, error, 1.0 - error, error, // col2
+ error, error, error, 1.0 - error); // col3
}
-#define ERROR_THRESHOLD 1e-7
-#define LOOSE_ERROR_THRESHOLD 1e-7
+constexpr double kErrorThreshold = 1e-7;
+
+// This test is to make it easier to understand the order of operations.
+TEST(XFormTest, PrePostOperations) {
+ auto m1 = Transform::Affine(1, 2, 3, 4, 5, 6);
+ auto m2 = m1;
+ m1.Translate(10, 20);
+ m2.PreConcat(Transform::MakeTranslation(10, 20));
+ EXPECT_EQ(m1, m2);
+
+ m1.PostTranslate(11, 22);
+ m2.PostConcat(Transform::MakeTranslation(11, 22));
+ EXPECT_EQ(m1, m2);
+
+ m1.Scale(3, 4);
+ m2.PreConcat(Transform::MakeScale(3, 4));
+ EXPECT_EQ(m1, m2);
+
+ m1.PostScale(5, 6);
+ m2.PostConcat(Transform::MakeScale(5, 6));
+ EXPECT_EQ(m1, m2);
+}
+
+// This test mostly overlaps with other tests, but similar to the above test,
+// this test may help understand how accumulated transforms are equivalent to
+// multiple mapping operations e.g. MapPoint().
+TEST(XFormTest, BasicOperations) {
+ // Just some arbitrary matrix that introduces no rounding, and is unlikely
+ // to commute with other operations.
+ auto m = Transform::ColMajor(2.f, 3.f, 5.f, 0.f, 7.f, 11.f, 13.f, 0.f, 17.f,
+ 19.f, 23.f, 0.f, 29.f, 31.f, 37.f, 1.f);
+
+ Point3F p(41.f, 43.f, 47.f);
+
+ EXPECT_EQ(Point3F(1211.f, 1520.f, 1882.f), m.MapPoint(p));
+
+ {
+ Transform n;
+ n.Scale(2.f);
+ EXPECT_EQ(Point3F(82.f, 86.f, 47.f), n.MapPoint(p));
+
+ Transform mn = m;
+ mn.Scale(2.f);
+ EXPECT_EQ(mn.MapPoint(p), m.MapPoint(n.MapPoint(p)));
+ }
+
+ {
+ Transform n;
+ n.Scale(2.f, 3.f);
+ EXPECT_EQ(Point3F(82.f, 129.f, 47.f), n.MapPoint(p));
+
+ Transform mn = m;
+ mn.Scale(2.f, 3.f);
+ EXPECT_EQ(mn.MapPoint(p), m.MapPoint(n.MapPoint(p)));
+ }
+
+ {
+ Transform n;
+ n.Scale3d(2.f, 3.f, 4.f);
+ EXPECT_EQ(Point3F(82.f, 129.f, 188.f), n.MapPoint(p));
+
+ Transform mn = m;
+ mn.Scale3d(2.f, 3.f, 4.f);
+ EXPECT_EQ(mn.MapPoint(p), m.MapPoint(n.MapPoint(p)));
+ }
+
+ {
+ Transform n;
+ n.Rotate(90.f);
+ EXPECT_FLOAT_EQ(0.f, (Point3F(-43.f, 41.f, 47.f) - n.MapPoint(p)).Length());
+
+ Transform mn = m;
+ mn.Rotate(90.f);
+ EXPECT_FLOAT_EQ(0.f, (mn.MapPoint(p) - m.MapPoint(n.MapPoint(p))).Length());
+ }
+
+ {
+ Transform n;
+ n.RotateAbout(10.f, 10.f, 10.f, 120.f);
+ EXPECT_FLOAT_EQ(0.f, (Point3F(47.f, 41.f, 43.f) - n.MapPoint(p)).Length());
+
+ Transform mn = m;
+ mn.RotateAbout(10.f, 10.f, 10.f, 120.f);
+ EXPECT_FLOAT_EQ(0.f, (mn.MapPoint(p) - m.MapPoint(n.MapPoint(p))).Length());
+ }
+
+ {
+ Transform n;
+ n.Translate(5.f, 6.f);
+ EXPECT_EQ(Point3F(46.f, 49.f, 47.f), n.MapPoint(p));
+
+ Transform mn = m;
+ mn.Translate(5.f, 6.f);
+ EXPECT_EQ(mn.MapPoint(p), m.MapPoint(n.MapPoint(p)));
+ }
+
+ {
+ Transform n;
+ n.Translate3d(5.f, 6.f, 7.f);
+ EXPECT_EQ(Point3F(46.f, 49.f, 54.f), n.MapPoint(p));
+
+ Transform mn = m;
+ mn.Translate3d(5.f, 6.f, 7.f);
+ EXPECT_EQ(mn.MapPoint(p), m.MapPoint(n.MapPoint(p)));
+ }
+
+ {
+ Transform nm = m;
+ nm.PostTranslate(5.f, 6.f);
+ EXPECT_EQ(nm.MapPoint(p), m.MapPoint(p) + Vector3dF(5.f, 6.f, 0.f));
+ }
+
+ {
+ Transform nm = m;
+ nm.PostTranslate3d(5.f, 6.f, 7.f);
+ EXPECT_EQ(nm.MapPoint(p), m.MapPoint(p) + Vector3dF(5.f, 6.f, 7.f));
+ }
+
+ {
+ Transform n;
+ n.Skew(45.f, -45.f);
+ EXPECT_FLOAT_EQ(0.f, (Point3F(84.f, 2.f, 47.f) - n.MapPoint(p)).Length());
+
+ Transform mn = m;
+ mn.Skew(45.f, -45.f);
+ EXPECT_FLOAT_EQ(0.f, (mn.MapPoint(p) - m.MapPoint(n.MapPoint(p))).Length());
+ }
+
+ {
+ Transform n;
+ n.SkewX(45.f);
+ EXPECT_FLOAT_EQ(0.f, (Point3F(84.f, 43.f, 47.f) - n.MapPoint(p)).Length());
+
+ Transform mn = m;
+ mn.SkewX(45.f);
+ EXPECT_FLOAT_EQ(0.f, (mn.MapPoint(p) - m.MapPoint(n.MapPoint(p))).Length());
+ }
+
+ {
+ Transform n;
+ n.SkewY(45.f);
+ EXPECT_FLOAT_EQ(0.f, (Point3F(41.f, 84.f, 47.f) - n.MapPoint(p)).Length());
+
+ Transform mn = m;
+ mn.SkewY(45.f);
+ EXPECT_FLOAT_EQ(0.f, (mn.MapPoint(p) - m.MapPoint(n.MapPoint(p))).Length());
+ }
+
+ {
+ Transform n;
+ n.ApplyPerspectiveDepth(94.f);
+ EXPECT_FLOAT_EQ(0.f, (Point3F(82.f, 86.f, 94.f) - n.MapPoint(p)).Length());
+
+ Transform mn = m;
+ mn.ApplyPerspectiveDepth(94.f);
+ EXPECT_FLOAT_EQ(0.f, (mn.MapPoint(p) - m.MapPoint(n.MapPoint(p))).Length());
+ }
+
+ {
+ Transform n = m;
+ n.Zoom(2.f);
+ Point3F expectation = p;
+ expectation.Scale(0.5f, 0.5f, 0.5f);
+ expectation = m.MapPoint(expectation);
+ expectation.Scale(2.f, 2.f, 2.f);
+ EXPECT_EQ(expectation, n.MapPoint(p));
+ }
+}
TEST(XFormTest, Equality) {
- Transform lhs, rhs, interpolated;
- rhs.matrix().set3x3(1, 2, 3, 4, 5, 6, 7, 8, 9);
+ Transform lhs, interpolated;
+ auto rhs = GetTestMatrix1();
interpolated = lhs;
for (int i = 0; i <= 100; ++i) {
for (int row = 0; row < 4; ++row) {
for (int col = 0; col < 4; ++col) {
- float a = lhs.matrix().get(row, col);
- float b = rhs.matrix().get(row, col);
+ float a = lhs.rc(row, col);
+ float b = rhs.rc(row, col);
float t = i / 100.0f;
- interpolated.matrix().set(row, col, a + (b - a) * t);
+ interpolated.set_rc(row, col, a + (b - a) * t);
}
}
if (i == 100) {
@@ -221,9 +382,8 @@
Transform translation;
translation.Translate(value.tx, value.ty);
xform = translation * xform;
- Point3F p1(value.x1, value.y1, 0);
+ Point3F p1 = xform.MapPoint(Point3F(value.x1, value.y1, 0));
Point3F p2(value.x2, value.y2, 0);
- xform.TransformPoint(&p1);
if (value.tx == value.tx && value.ty == value.ty) {
EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
}
@@ -246,9 +406,8 @@
Transform scale;
scale.Scale(value.scale, value.scale);
xform = scale * xform;
- Point3F p1(value.before, value.before, 0);
+ Point3F p1 = xform.MapPoint(Point3F(value.before, value.before, 0));
Point3F p2(value.after, value.after, 0);
- xform.TransformPoint(&p1);
if (value.scale == value.scale) {
EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
}
@@ -274,16 +433,31 @@
Transform rotation;
rotation.Rotate(value.degrees);
xform = rotation * xform;
- Point3F p1(value.x1, value.y1, 0);
+ Point3F p1 = xform.MapPoint(Point3F(value.x1, value.y1, 0));
Point3F p2(value.x2, value.y2, 0);
- xform.TransformPoint(&p1);
if (value.degrees == value.degrees) {
- EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
+ EXPECT_POINT3F_NEAR(p1, p2, 0.0001f);
}
}
}
-TEST(XFormTest, SetTranslate) {
+TEST(XFormTest, ConcatSelf) {
+ auto a = Transform::ColMajor(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17);
+ auto expected_a_times_a =
+ Transform::ColMajor(132, 146, 160, 174, 260, 290, 320, 350, 388, 434, 480,
+ 526, 516, 578, 640, 702);
+ a.PreConcat(a);
+ EXPECT_EQ(expected_a_times_a, a);
+
+ a = Transform::Affine(2, 3, 4, 5, 6, 7);
+ expected_a_times_a = Transform::Affine(16, 21, 28, 37, 46, 60);
+ a.PreConcat(a);
+ EXPECT_TRUE(a.Is2dTransform());
+ EXPECT_EQ(expected_a_times_a, a);
+}
+
+TEST(XFormTest, Translate) {
static const struct TestCase {
int x1;
int y1;
@@ -319,17 +493,19 @@
break;
}
p0 = p1;
- xform.TransformPoint(&p1);
+ p1 = xform.MapPoint(p1);
if (value.tx == value.tx && value.ty == value.ty) {
EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
- xform.TransformPointReverse(&p1);
- EXPECT_TRUE(PointsAreNearlyEqual(p1, p0));
+ const absl::optional<Point3F> transformed_p1 =
+ xform.InverseMapPoint(p1);
+ ASSERT_TRUE(transformed_p1.has_value());
+ EXPECT_TRUE(PointsAreNearlyEqual(transformed_p1.value(), p0));
}
}
}
}
-TEST(XFormTest, SetScale) {
+TEST(XFormTest, Scale) {
static const struct TestCase {
int before;
float s;
@@ -364,12 +540,14 @@
break;
}
p0 = p1;
- xform.TransformPoint(&p1);
+ p1 = xform.MapPoint(p1);
if (value.s == value.s) {
EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
if (value.s != 0.0f) {
- xform.TransformPointReverse(&p1);
- EXPECT_TRUE(PointsAreNearlyEqual(p1, p0));
+ const absl::optional<Point3F> transformed_p1 =
+ xform.InverseMapPoint(p1);
+ ASSERT_TRUE(transformed_p1.has_value());
+ EXPECT_TRUE(PointsAreNearlyEqual(transformed_p1.value(), p0));
}
}
}
@@ -401,10 +579,11 @@
xform.Rotate(value.degree);
// just want to make sure that we don't crash in the case of NaN.
if (value.degree == value.degree) {
- xform.TransformPoint(&p1);
+ p1 = xform.MapPoint(p1);
EXPECT_TRUE(PointsAreNearlyEqual(p1, p2));
- xform.TransformPointReverse(&p1);
- EXPECT_TRUE(PointsAreNearlyEqual(p1, p0));
+ const absl::optional<Point3F> transformed_p1 = xform.InverseMapPoint(p1);
+ ASSERT_TRUE(transformed_p1.has_value());
+ EXPECT_TRUE(PointsAreNearlyEqual(transformed_p1.value(), p0));
}
}
}
@@ -429,9 +608,8 @@
Transform translation;
translation.Translate(value.tx, value.ty);
xform = translation * xform;
- Point p1(value.x1, value.y1);
+ Point p1 = xform.MapPoint(Point(value.x1, value.y1));
Point p2(value.x2, value.y2);
- xform.TransformPoint(&p1);
if (value.tx == value.tx && value.ty == value.ty) {
EXPECT_EQ(p1.x(), p2.x());
EXPECT_EQ(p1.y(), p2.y());
@@ -456,9 +634,8 @@
Transform scale;
scale.Scale(value.scale, value.scale);
xform = scale * xform;
- Point p1(value.before, value.before);
+ Point p1 = xform.MapPoint(Point(value.before, value.before));
Point p2(value.after, value.after);
- xform.TransformPoint(&p1);
if (value.scale == value.scale) {
EXPECT_EQ(p1.x(), p2.x());
EXPECT_EQ(p1.y(), p2.y());
@@ -483,9 +660,8 @@
Transform rotation;
rotation.Rotate(value.degrees);
xform = rotation * xform;
- Point p1(value.x1, value.y1);
+ Point p1 = xform.MapPoint(Point(value.x1, value.y1));
Point p2(value.x2, value.y2);
- xform.TransformPoint(&p1);
if (value.degrees == value.degrees) {
EXPECT_EQ(p1.x(), p2.x());
EXPECT_EQ(p1.y(), p2.y());
@@ -531,13 +707,15 @@
break;
}
p0 = p1;
- xform.TransformPoint(&p1);
+ p1 = xform.MapPoint(p1);
if (value.tx == value.tx && value.ty == value.ty) {
EXPECT_EQ(p1.x(), p2.x());
EXPECT_EQ(p1.y(), p2.y());
- xform.TransformPointReverse(&p1);
- EXPECT_EQ(p1.x(), p0.x());
- EXPECT_EQ(p1.y(), p0.y());
+ const absl::optional<Point> transformed_p1 =
+ xform.InverseMapPoint(p1);
+ ASSERT_TRUE(transformed_p1.has_value());
+ EXPECT_EQ(transformed_p1->x(), p0.x());
+ EXPECT_EQ(transformed_p1->y(), p0.y());
}
}
}
@@ -580,14 +758,16 @@
break;
}
p0 = p1;
- xform.TransformPoint(&p1);
+ p1 = xform.MapPoint(p1);
if (value.s == value.s) {
EXPECT_EQ(p1.x(), p2.x());
EXPECT_EQ(p1.y(), p2.y());
if (value.s != 0.0f) {
- xform.TransformPointReverse(&p1);
- EXPECT_EQ(p1.x(), p0.x());
- EXPECT_EQ(p1.y(), p0.y());
+ const absl::optional<Point> transformed_p1 =
+ xform.InverseMapPoint(p1);
+ ASSERT_TRUE(transformed_p1.has_value());
+ EXPECT_EQ(transformed_p1->x(), p0.x());
+ EXPECT_EQ(transformed_p1->y(), p0.y());
}
}
}
@@ -620,29 +800,28 @@
xform.Rotate(value.degree + j * epsilon);
// just want to make sure that we don't crash in the case of NaN.
if (value.degree == value.degree) {
- xform.TransformPoint(&pt);
+ pt = xform.MapPoint(pt);
EXPECT_EQ(value.xprime, pt.x());
EXPECT_EQ(value.yprime, pt.y());
- xform.TransformPointReverse(&pt);
- EXPECT_EQ(pt.x(), value.x);
- EXPECT_EQ(pt.y(), value.y);
+ const absl::optional<Point> transformed_pt = xform.InverseMapPoint(pt);
+ ASSERT_TRUE(transformed_pt.has_value());
+ EXPECT_EQ(transformed_pt->x(), value.x);
+ EXPECT_EQ(transformed_pt->y(), value.y);
}
}
}
}
-TEST(XFormTest, TransformPointWithExtremePerspective) {
+TEST(XFormTest, MapPointWithExtremePerspective) {
Point3F point(1.f, 1.f, 1.f);
Transform perspective;
perspective.ApplyPerspectiveDepth(1.f);
- Point3F transformed = point;
- perspective.TransformPoint(&transformed);
+ Point3F transformed = perspective.MapPoint(point);
EXPECT_EQ(point.ToString(), transformed.ToString());
- transformed = point;
perspective.MakeIdentity();
perspective.ApplyPerspectiveDepth(1.1f);
- perspective.TransformPoint(&transformed);
+ transformed = perspective.MapPoint(point);
EXPECT_FLOAT_EQ(11.f, transformed.x());
EXPECT_FLOAT_EQ(11.f, transformed.y());
EXPECT_FLOAT_EQ(11.f, transformed.z());
@@ -655,9 +834,9 @@
to.Translate3d(1, 1, 1);
double t = i / 9.0;
EXPECT_TRUE(to.Blend(from, t));
- EXPECT_FLOAT_EQ(t, to.matrix().get(0, 3));
- EXPECT_FLOAT_EQ(t, to.matrix().get(1, 3));
- EXPECT_FLOAT_EQ(t, to.matrix().get(2, 3));
+ EXPECT_FLOAT_EQ(t, to.rc(0, 3));
+ EXPECT_FLOAT_EQ(t, to.rc(1, 3));
+ EXPECT_FLOAT_EQ(t, to.rc(2, 3));
}
}
@@ -701,6 +880,8 @@
EXPECT_TRUE(MatricesAreNearlyEqual(expected1, to) ||
MatricesAreNearlyEqual(expected2, to))
+ << "to: " << to.ToString() << "expected1: " << expected1.ToString()
+ << "expected2: " << expected2.ToString()
<< "axis: " << axis.ToString() << ", i: " << i;
}
}
@@ -714,9 +895,9 @@
double s1 = i / 9.0;
double s2 = 1 - s1;
EXPECT_TRUE(to.Blend(from, s1));
- EXPECT_FLOAT_EQ(5 * s1 + s2, to.matrix().get(0, 0)) << "i: " << i;
- EXPECT_FLOAT_EQ(4 * s1 + s2, to.matrix().get(1, 1)) << "i: " << i;
- EXPECT_FLOAT_EQ(3 * s1 + s2, to.matrix().get(2, 2)) << "i: " << i;
+ EXPECT_FLOAT_EQ(5 * s1 + s2, to.rc(0, 0)) << "i: " << i;
+ EXPECT_FLOAT_EQ(4 * s1 + s2, to.rc(1, 1)) << "i: " << i;
+ EXPECT_FLOAT_EQ(3 * s1 + s2, to.rc(2, 2)) << "i: " << i;
}
}
@@ -729,7 +910,9 @@
Transform expected;
expected.Skew(t * 10, t * 5);
EXPECT_TRUE(to.Blend(from, t));
- EXPECT_TRUE(MatricesAreNearlyEqual(expected, to));
+ EXPECT_TRUE(MatricesAreNearlyEqual(expected, to))
+ << expected.ToString() << "\n"
+ << to.ToString();
}
}
@@ -771,8 +954,12 @@
TEST(XFormTest, CannotBlendSingularMatrix) {
Transform from;
Transform to;
- to.matrix().set(1, 1, 0);
- EXPECT_FALSE(to.Blend(from, 0.5));
+ to.set_rc(1, 1, 0);
+ Transform original_to = to;
+ EXPECT_FALSE(to.Blend(from, 0.25));
+ EXPECT_EQ(original_to, to);
+ EXPECT_FALSE(to.Blend(from, 0.75));
+ EXPECT_EQ(original_to, to);
}
TEST(XFormTest, VerifyBlendForTranslation) {
@@ -788,26 +975,26 @@
to = Transform();
to.Translate3d(200.0, 100.0, 300.0);
to.Blend(from, 0.25);
- EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 125.0f, to);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 175.0f, to);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 150.0f, to);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, 0.0f, 125.0f, to);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 175.0f, to);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 150.0f, to);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
to = Transform();
to.Translate3d(200.0, 100.0, 300.0);
to.Blend(from, 0.5);
- EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 150.0f, to);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 150.0f, to);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 200.0f, to);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, 0.0f, 150.0f, to);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 150.0f, to);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 200.0f, to);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
to = Transform();
to.Translate3d(200.0, 100.0, 300.0);
to.Blend(from, 1.0);
- EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 200.0f, to);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 100.0f, to);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 300.0f, to);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, 0.0f, 200.0f, to);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 100.0f, to);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 300.0f, to);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
}
TEST(XFormTest, VerifyBlendForScale) {
@@ -823,26 +1010,26 @@
to = Transform();
to.Scale3d(200.0, 100.0, 300.0);
to.Blend(from, 0.25);
- EXPECT_ROW1_EQ(125.0f, 0.0f, 0.0f, 0.0f, to);
- EXPECT_ROW2_EQ(0.0f, 175.0f, 0.0f, 0.0f, to);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 150.0f, 0.0f, to);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_EQ(125.0f, 0.0f, 0.0f, 0.0f, to);
+ EXPECT_ROW1_EQ(0.0f, 175.0f, 0.0f, 0.0f, to);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 150.0f, 0.0f, to);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
to = Transform();
to.Scale3d(200.0, 100.0, 300.0);
to.Blend(from, 0.5);
- EXPECT_ROW1_EQ(150.0f, 0.0f, 0.0f, 0.0f, to);
- EXPECT_ROW2_EQ(0.0f, 150.0f, 0.0f, 0.0f, to);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 200.0f, 0.0f, to);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_EQ(150.0f, 0.0f, 0.0f, 0.0f, to);
+ EXPECT_ROW1_EQ(0.0f, 150.0f, 0.0f, 0.0f, to);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 200.0f, 0.0f, to);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
to = Transform();
to.Scale3d(200.0, 100.0, 300.0);
to.Blend(from, 1.0);
- EXPECT_ROW1_EQ(200.0f, 0.0f, 0.0f, 0.0f, to);
- EXPECT_ROW2_EQ(0.0f, 100.0f, 0.0f, 0.0f, to);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 300.0f, 0.0f, to);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_EQ(200.0f, 0.0f, 0.0f, 0.0f, to);
+ EXPECT_ROW1_EQ(0.0f, 100.0f, 0.0f, 0.0f, to);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 300.0f, 0.0f, to);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
}
TEST(XFormTest, VerifyBlendForSkew) {
@@ -859,26 +1046,26 @@
to = Transform();
to.Skew(45.0, 0.0);
to.Blend(from, 0.5);
- EXPECT_ROW1_EQ(1.0f, 0.5f, 0.0f, 0.0f, to);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_EQ(1.0f, 0.5f, 0.0f, 0.0f, to);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
to = Transform();
to.Skew(45.0, 0.0);
to.Blend(from, 0.25);
- EXPECT_ROW1_EQ(1.0f, 0.25f, 0.0f, 0.0f, to);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_EQ(1.0f, 0.25f, 0.0f, 0.0f, to);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
to = Transform();
to.Skew(45.0, 0.0);
to.Blend(from, 1.0);
- EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, to);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_EQ(1.0f, 1.0f, 0.0f, 0.0f, to);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 0.0f, to);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
// NOTE CAREFULLY: Decomposition of skew and rotation terms of the matrix
// is inherently underconstrained, and so it does not always compute the
@@ -909,54 +1096,54 @@
to = Transform();
to.Skew(0.0, 45.0);
to.Blend(from, 0.25);
- EXPECT_LT(1.0, to.matrix().get(0, 0));
- EXPECT_GT(1.5, to.matrix().get(0, 0));
- EXPECT_LT(0.0, to.matrix().get(0, 1));
- EXPECT_GT(0.5, to.matrix().get(0, 1));
- EXPECT_FLOAT_EQ(0.0, to.matrix().get(0, 2));
- EXPECT_FLOAT_EQ(0.0, to.matrix().get(0, 3));
+ EXPECT_LT(1.0, to.rc(0, 0));
+ EXPECT_GT(1.5, to.rc(0, 0));
+ EXPECT_LT(0.0, to.rc(0, 1));
+ EXPECT_GT(0.5, to.rc(0, 1));
+ EXPECT_FLOAT_EQ(0.0, to.rc(0, 2));
+ EXPECT_FLOAT_EQ(0.0, to.rc(0, 3));
- EXPECT_LT(0.0, to.matrix().get(1, 0));
- EXPECT_GT(0.5, to.matrix().get(1, 0));
- EXPECT_LT(0.0, to.matrix().get(1, 1));
- EXPECT_GT(1.0, to.matrix().get(1, 1));
- EXPECT_FLOAT_EQ(0.0, to.matrix().get(1, 2));
- EXPECT_FLOAT_EQ(0.0, to.matrix().get(1, 3));
+ EXPECT_LT(0.0, to.rc(1, 0));
+ EXPECT_GT(0.5, to.rc(1, 0));
+ EXPECT_LT(0.0, to.rc(1, 1));
+ EXPECT_GT(1.0, to.rc(1, 1));
+ EXPECT_FLOAT_EQ(0.0, to.rc(1, 2));
+ EXPECT_FLOAT_EQ(0.0, to.rc(1, 3));
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
to = Transform();
to.Skew(0.0, 45.0);
to.Blend(from, 0.5);
- EXPECT_LT(1.0, to.matrix().get(0, 0));
- EXPECT_GT(1.5, to.matrix().get(0, 0));
- EXPECT_LT(0.0, to.matrix().get(0, 1));
- EXPECT_GT(0.5, to.matrix().get(0, 1));
- EXPECT_FLOAT_EQ(0.0, to.matrix().get(0, 2));
- EXPECT_FLOAT_EQ(0.0, to.matrix().get(0, 3));
+ EXPECT_LT(1.0, to.rc(0, 0));
+ EXPECT_GT(1.5, to.rc(0, 0));
+ EXPECT_LT(0.0, to.rc(0, 1));
+ EXPECT_GT(0.5, to.rc(0, 1));
+ EXPECT_FLOAT_EQ(0.0, to.rc(0, 2));
+ EXPECT_FLOAT_EQ(0.0, to.rc(0, 3));
- EXPECT_LT(0.0, to.matrix().get(1, 0));
- EXPECT_GT(1.0, to.matrix().get(1, 0));
- EXPECT_LT(0.0, to.matrix().get(1, 1));
- EXPECT_GT(1.0, to.matrix().get(1, 1));
- EXPECT_FLOAT_EQ(0.0, to.matrix().get(1, 2));
- EXPECT_FLOAT_EQ(0.0, to.matrix().get(1, 3));
+ EXPECT_LT(0.0, to.rc(1, 0));
+ EXPECT_GT(1.0, to.rc(1, 0));
+ EXPECT_LT(0.0, to.rc(1, 1));
+ EXPECT_GT(1.0, to.rc(1, 1));
+ EXPECT_FLOAT_EQ(0.0, to.rc(1, 2));
+ EXPECT_FLOAT_EQ(0.0, to.rc(1, 3));
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
to = Transform();
to.Skew(0.0, 45.0);
to.Blend(from, 1.0);
- EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(1.0, 1.0, 0.0, 0.0, to, LOOSE_ERROR_THRESHOLD);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_NEAR(1.0, 0.0, 0.0, 0.0, to, kErrorThreshold);
+ EXPECT_ROW1_NEAR(1.0, 1.0, 0.0, 0.0, to, kErrorThreshold);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, to);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
}
-TEST(XFormTest, VerifyBlendForRotationAboutX) {
+TEST(XFormTest, BlendForRotationAboutX) {
// Even though.Blending uses quaternions, axis-aligned rotations should.
// Blend the same with quaternions or Euler angles. So we can test
// rotation.Blending by comparing against manually specified matrices from
@@ -975,34 +1162,34 @@
to = Transform();
to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
to.Blend(from, 0.25);
- EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(0.0, std::cos(expectedRotationAngle),
- -std::sin(expectedRotationAngle), 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW3_NEAR(0.0, std::sin(expectedRotationAngle),
- std::cos(expectedRotationAngle), 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_EQ(1.0, 0.0, 0.0, 0.0, to);
+ EXPECT_ROW1_NEAR(0.0, std::cos(expectedRotationAngle),
+ -std::sin(expectedRotationAngle), 0.0, to, kErrorThreshold);
+ EXPECT_ROW2_NEAR(0.0, std::sin(expectedRotationAngle),
+ std::cos(expectedRotationAngle), 0.0, to, kErrorThreshold);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
expectedRotationAngle = gfx::DegToRad(45.0);
to = Transform();
to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
to.Blend(from, 0.5);
- EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(0.0, std::cos(expectedRotationAngle),
- -std::sin(expectedRotationAngle), 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW3_NEAR(0.0, std::sin(expectedRotationAngle),
- std::cos(expectedRotationAngle), 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_EQ(1.0, 0.0, 0.0, 0.0, to);
+ EXPECT_ROW1_NEAR(0.0, std::cos(expectedRotationAngle),
+ -std::sin(expectedRotationAngle), 0.0, to, kErrorThreshold);
+ EXPECT_ROW2_NEAR(0.0, std::sin(expectedRotationAngle),
+ std::cos(expectedRotationAngle), 0.0, to, kErrorThreshold);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
to = Transform();
to.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
to.Blend(from, 1.0);
- EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_EQ(1.0, 0.0, 0.0, 0.0, to);
+ EXPECT_ROW1_NEAR(0.0, 0.0, -1.0, 0.0, to, kErrorThreshold);
+ EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, kErrorThreshold);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
}
-TEST(XFormTest, VerifyBlendForRotationAboutY) {
+TEST(XFormTest, BlendForRotationAboutY) {
Transform from;
from.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 0.0);
@@ -1016,34 +1203,34 @@
to = Transform();
to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
to.Blend(from, 0.25);
- EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle), 0.0,
- std::sin(expectedRotationAngle), 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle), 0.0,
- std::cos(expectedRotationAngle), 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_NEAR(std::cos(expectedRotationAngle), 0.0,
+ std::sin(expectedRotationAngle), 0.0, to, kErrorThreshold);
+ EXPECT_ROW1_EQ(0.0, 1.0, 0.0, 0.0, to);
+ EXPECT_ROW2_NEAR(-std::sin(expectedRotationAngle), 0.0,
+ std::cos(expectedRotationAngle), 0.0, to, kErrorThreshold);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
expectedRotationAngle = gfx::DegToRad(45.0);
to = Transform();
to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
to.Blend(from, 0.5);
- EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle), 0.0,
- std::sin(expectedRotationAngle), 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW3_NEAR(-std::sin(expectedRotationAngle), 0.0,
- std::cos(expectedRotationAngle), 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_NEAR(std::cos(expectedRotationAngle), 0.0,
+ std::sin(expectedRotationAngle), 0.0, to, kErrorThreshold);
+ EXPECT_ROW1_EQ(0.0, 1.0, 0.0, 0.0, to);
+ EXPECT_ROW2_NEAR(-std::sin(expectedRotationAngle), 0.0,
+ std::cos(expectedRotationAngle), 0.0, to, kErrorThreshold);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
to = Transform();
to.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
to.Blend(from, 1.0);
- EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(0.0, 1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_NEAR(0.0, 0.0, 1.0, 0.0, to, kErrorThreshold);
+ EXPECT_ROW1_EQ(0.0, 1.0, 0.0, 0.0, to);
+ EXPECT_ROW2_NEAR(-1.0, 0.0, 0.0, 0.0, to, kErrorThreshold);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
}
-TEST(XFormTest, VerifyBlendForRotationAboutZ) {
+TEST(XFormTest, BlendForRotationAboutZ) {
Transform from;
from.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 0.0);
@@ -1057,38 +1244,38 @@
to = Transform();
to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
to.Blend(from, 0.25);
- EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
+ EXPECT_ROW0_NEAR(std::cos(expectedRotationAngle),
-std::sin(expectedRotationAngle), 0.0, 0.0, to,
- ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
+ kErrorThreshold);
+ EXPECT_ROW1_NEAR(std::sin(expectedRotationAngle),
std::cos(expectedRotationAngle), 0.0, 0.0, to,
- ERROR_THRESHOLD);
- EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ kErrorThreshold);
+ EXPECT_ROW2_EQ(0.0, 0.0, 1.0, 0.0, to);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
expectedRotationAngle = gfx::DegToRad(45.0);
to = Transform();
to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
to.Blend(from, 0.5);
- EXPECT_ROW1_NEAR(std::cos(expectedRotationAngle),
+ EXPECT_ROW0_NEAR(std::cos(expectedRotationAngle),
-std::sin(expectedRotationAngle), 0.0, 0.0, to,
- ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(std::sin(expectedRotationAngle),
+ kErrorThreshold);
+ EXPECT_ROW1_NEAR(std::sin(expectedRotationAngle),
std::cos(expectedRotationAngle), 0.0, 0.0, to,
- ERROR_THRESHOLD);
- EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ kErrorThreshold);
+ EXPECT_ROW2_EQ(0.0, 0.0, 1.0, 0.0, to);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
to = Transform();
to.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
to.Blend(from, 1.0);
- EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW3_NEAR(0.0, 0.0, 1.0, 0.0, to, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
+ EXPECT_ROW0_NEAR(0.0, -1.0, 0.0, 0.0, to, kErrorThreshold);
+ EXPECT_ROW1_NEAR(1.0, 0.0, 0.0, 0.0, to, kErrorThreshold);
+ EXPECT_ROW2_EQ(0.0, 0.0, 1.0, 0.0, to);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, to);
}
-TEST(XFormTest, VerifyBlendForCompositeTransform) {
+TEST(XFormTest, BlendForCompositeTransform) {
// Verify that the.Blending was done with a decomposition in correct order
// by blending a composite transform. Using matrix x vector notation
// (Ax = b, where x is column vector), the ordering should be:
@@ -1101,18 +1288,18 @@
Transform from;
Transform to;
- Transform expectedEndOfAnimation;
- expectedEndOfAnimation.ApplyPerspectiveDepth(1.0);
- expectedEndOfAnimation.Translate3d(10.0, 20.0, 30.0);
- expectedEndOfAnimation.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 25.0);
- expectedEndOfAnimation.Skew(0.0, 45.0);
- expectedEndOfAnimation.Scale3d(6.0, 7.0, 8.0);
+ Transform expected_end_of_animation;
+ expected_end_of_animation.ApplyPerspectiveDepth(1.0);
+ expected_end_of_animation.Translate3d(10.0, 20.0, 30.0);
+ expected_end_of_animation.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 25.0);
+ expected_end_of_animation.Skew(0.0, 45.0);
+ expected_end_of_animation.Scale3d(6.0, 7.0, 8.0);
- to = expectedEndOfAnimation;
+ to = expected_end_of_animation;
to.Blend(from, 0.0);
EXPECT_EQ(from, to);
- to = expectedEndOfAnimation;
+ to = expected_end_of_animation;
// We short circuit if blend is >= 1, so to check the numerics, we will
// check that we get close to what we expect when we're nearly done
// interpolating.
@@ -1121,26 +1308,208 @@
// Recomposing the matrix results in a normalized matrix, so to verify we
// need to normalize the expectedEndOfAnimation before comparing elements.
// Normalizing means dividing everything by expectedEndOfAnimation.m44().
- Transform normalizedExpectedEndOfAnimation = expectedEndOfAnimation;
- Transform normalizationMatrix;
- normalizationMatrix.matrix().set(
- 0.0, 0.0,
- SkDoubleToScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
- normalizationMatrix.matrix().set(
- 1.0, 1.0,
- SkDoubleToScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
- normalizationMatrix.matrix().set(
- 2.0, 2.0,
- SkDoubleToScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
- normalizationMatrix.matrix().set(
- 3.0, 3.0,
- SkDoubleToScalar(1 / expectedEndOfAnimation.matrix().get(3.0, 3.0)));
- normalizedExpectedEndOfAnimation.PreconcatTransform(normalizationMatrix);
+ Transform normalized_expected_end_of_animation = expected_end_of_animation;
+ Transform normalization_matrix;
+ double inv_w = 1.0 / expected_end_of_animation.rc(3, 3);
+ normalization_matrix.set_rc(0, 0, inv_w);
+ normalization_matrix.set_rc(1, 1, inv_w);
+ normalization_matrix.set_rc(2, 2, inv_w);
+ normalization_matrix.set_rc(3, 3, inv_w);
+ normalized_expected_end_of_animation.PreConcat(normalization_matrix);
- EXPECT_TRUE(MatricesAreNearlyEqual(normalizedExpectedEndOfAnimation, to));
+ EXPECT_TRUE(MatricesAreNearlyEqual(normalized_expected_end_of_animation, to));
}
-TEST(XFormTest, DecomposedTransformCtor) {
+TEST(XFormTest, Blend2dXFlip) {
+ // Test 2D x-flip (crbug.com/797472).
+ auto from = Transform::Affine(1, 0, 0, 1, 100, 150);
+ auto to = Transform::Affine(-1, 0, 0, 1, 400, 150);
+
+ EXPECT_TRUE(from.Is2dTransform());
+ EXPECT_TRUE(to.Is2dTransform());
+
+ // OK for interpolated transform to be degenerate.
+ Transform result = to;
+ EXPECT_TRUE(result.Blend(from, 0.5));
+ auto expected = Transform::Affine(0, 0, 0, 1, 250, 150);
+ EXPECT_TRANSFORM_EQ(expected, result);
+}
+
+TEST(XFormTest, Blend2dRotationDirection) {
+ // Interpolate taking shorter rotation path.
+ auto from =
+ Transform::Affine(-0.5, 0.86602575498, -0.86602575498, -0.5, 0, 0);
+ auto to = Transform::Affine(-0.5, -0.86602575498, 0.86602575498, -0.5, 0, 0);
+
+ // Expect clockwise Rotation.
+ Transform result = to;
+ EXPECT_TRUE(result.Blend(from, 0.5));
+ auto expected = Transform::Affine(-1, 0, 0, -1, 0, 0);
+ EXPECT_TRANSFORM_EQ(expected, result);
+
+ // Reverse from and to.
+ // Expect same midpoint with counter-clockwise rotation.
+ result = from;
+ EXPECT_TRUE(result.Blend(to, 0.5));
+ EXPECT_TRANSFORM_EQ(expected, result);
+}
+
+gfx::DecomposedTransform GetRotationDecomp(double x,
+ double y,
+ double z,
+ double w) {
+ gfx::DecomposedTransform decomp;
+ decomp.quaternion = gfx::Quaternion(x, y, z, w);
+ return decomp;
+}
+
+const double kCos30deg = std::cos(base::kPiDouble / 6);
+const double kSin30deg = 0.5;
+const double kRoot2 = std::sqrt(2);
+
+TEST(XFormTest, QuaternionFromRotationMatrix) {
+ // Test rotation around each axis.
+
+ Transform m;
+ m.RotateAbout(1, 0, 0, 60);
+ absl::optional<DecomposedTransform> decomp = m.Decompose();
+ ASSERT_TRUE(decomp);
+ EXPECT_QUATERNION_NEAR(decomp->quaternion,
+ gfx::Quaternion(kSin30deg, 0, 0, kCos30deg), 1e-6);
+
+ m.MakeIdentity();
+ m.RotateAbout(0, 1, 0, 60);
+ decomp = m.Decompose();
+ ASSERT_TRUE(decomp);
+ EXPECT_QUATERNION_NEAR(decomp->quaternion,
+ gfx::Quaternion(0, kSin30deg, 0, kCos30deg), 1e-6);
+
+ m.MakeIdentity();
+ m.RotateAbout(0, 0, 1, 60);
+ decomp = m.Decompose();
+ ASSERT_TRUE(decomp);
+ EXPECT_QUATERNION_NEAR(decomp->quaternion,
+ gfx::Quaternion(0, 0, kSin30deg, kCos30deg), 1e-6);
+
+ // Test rotation around non-axis aligned vector.
+
+ m.MakeIdentity();
+ m.RotateAbout(1, 1, 0, 60);
+ decomp = m.Decompose();
+ ASSERT_TRUE(decomp);
+ EXPECT_QUATERNION_NEAR(
+ decomp->quaternion,
+ gfx::Quaternion(kSin30deg / kRoot2, kSin30deg / kRoot2, 0, kCos30deg),
+ 1e-6);
+
+ // Test edge tests.
+
+ // Cases where q_w = 0. In such cases we resort to basing the calculations on
+ // the largest diagonal element in the rotation matrix to ensure numerical
+ // stability.
+
+ m.MakeIdentity();
+ m.RotateAbout(1, 0, 0, 180);
+ decomp = m.Decompose();
+ ASSERT_TRUE(decomp);
+ EXPECT_QUATERNION_NEAR(decomp->quaternion, gfx::Quaternion(1, 0, 0, 0), 1e-6);
+
+ m.MakeIdentity();
+ m.RotateAbout(0, 1, 0, 180);
+ decomp = m.Decompose();
+ ASSERT_TRUE(decomp);
+ EXPECT_QUATERNION_NEAR(decomp->quaternion, gfx::Quaternion(0, 1, 0, 0), 1e-6);
+
+ m.MakeIdentity();
+ m.RotateAbout(0, 0, 1, 180);
+ decomp = m.Decompose();
+ ASSERT_TRUE(decomp);
+ EXPECT_QUATERNION_NEAR(decomp->quaternion, gfx::Quaternion(0, 0, 1, 0), 1e-6);
+
+ // No rotation.
+
+ m.MakeIdentity();
+ decomp = m.Decompose();
+ ASSERT_TRUE(decomp);
+ EXPECT_QUATERNION_NEAR(decomp->quaternion, gfx::Quaternion(0, 0, 0, 1), 1e-6);
+
+ m.MakeIdentity();
+ m.RotateAbout(0, 0, 1, 360);
+ decomp = m.Decompose();
+ ASSERT_TRUE(decomp);
+ EXPECT_QUATERNION_NEAR(decomp->quaternion, gfx::Quaternion(0, 0, 0, 1), 1e-6);
+}
+
+TEST(XFormTest, QuaternionToRotationMatrixTest) {
+ // Test rotation about each axis.
+ Transform rotate_x_60deg;
+ rotate_x_60deg.RotateAboutXAxis(60);
+ EXPECT_TRANSFORM_EQ(rotate_x_60deg, Transform::Compose(GetRotationDecomp(
+ kSin30deg, 0, 0, kCos30deg)));
+
+ Transform rotate_y_60deg;
+ rotate_y_60deg.RotateAboutYAxis(60);
+ EXPECT_TRANSFORM_EQ(rotate_y_60deg, Transform::Compose(GetRotationDecomp(
+ 0, kSin30deg, 0, kCos30deg)));
+
+ Transform rotate_z_60deg;
+ rotate_z_60deg.RotateAboutZAxis(60);
+ EXPECT_TRANSFORM_EQ(rotate_z_60deg, Transform::Compose(GetRotationDecomp(
+ 0, 0, kSin30deg, kCos30deg)));
+
+ // Test non-axis aligned rotation
+ Transform rotate_xy_60deg;
+ rotate_xy_60deg.RotateAbout(1, 1, 0, 60);
+ EXPECT_TRANSFORM_EQ(rotate_xy_60deg, Transform::Compose(GetRotationDecomp(
+ kSin30deg / kRoot2,
+ kSin30deg / kRoot2, 0, kCos30deg)));
+
+ // Test 180deg rotation.
+ auto rotate_z_180deg = Transform::Affine(-1, 0, 0, -1, 0, 0);
+ EXPECT_TRANSFORM_EQ(rotate_z_180deg,
+ Transform::Compose(GetRotationDecomp(0, 0, 1, 0)));
+}
+
+TEST(XFormTest, QuaternionInterpolation) {
+ // Rotate from identity matrix.
+ Transform from_matrix;
+ Transform to_matrix;
+ to_matrix.RotateAbout(0, 0, 1, 120);
+ to_matrix.Blend(from_matrix, 0.5);
+ Transform rotate_z_60;
+ rotate_z_60.Rotate(60);
+ EXPECT_TRANSFORM_EQ(rotate_z_60, to_matrix);
+
+ // Rotate to identity matrix.
+ from_matrix.MakeIdentity();
+ from_matrix.RotateAbout(0, 0, 1, 120);
+ to_matrix.MakeIdentity();
+ EXPECT_TRUE(to_matrix.Blend(from_matrix, 0.5));
+ EXPECT_TRANSFORM_EQ(rotate_z_60, to_matrix);
+
+ // Interpolation about a common axis of rotation.
+ from_matrix.MakeIdentity();
+ from_matrix.RotateAbout(1, 1, 0, 45);
+ to_matrix.MakeIdentity();
+ from_matrix.RotateAbout(1, 1, 0, 135);
+ EXPECT_TRUE(to_matrix.Blend(from_matrix, 0.5));
+ Transform rotate_xy_90;
+ rotate_xy_90.RotateAbout(1, 1, 0, 90);
+ EXPECT_TRANSFORM_NEAR(rotate_xy_90, to_matrix, 1e-15);
+
+ // Interpolation without a common axis of rotation.
+
+ from_matrix.MakeIdentity();
+ from_matrix.RotateAbout(1, 0, 0, 90);
+ to_matrix.MakeIdentity();
+ to_matrix.RotateAbout(0, 0, 1, 90);
+ EXPECT_TRUE(to_matrix.Blend(from_matrix, 0.5));
+ Transform expected;
+ expected.RotateAbout(1 / kRoot2, 0, 1 / kRoot2, 70.528778372);
+ EXPECT_TRANSFORM_EQ(expected, to_matrix);
+}
+
+TEST(XFormTest, ComposeIdentity) {
DecomposedTransform decomp;
for (int i = 0; i < 3; ++i) {
EXPECT_EQ(0.0, decomp.translate[i]);
@@ -1155,12 +1524,10 @@
EXPECT_EQ(0.0, decomp.quaternion.z());
EXPECT_EQ(1.0, decomp.quaternion.w());
- Transform identity;
- Transform composed = ComposeTransform(decomp);
- EXPECT_TRUE(MatricesAreNearlyEqual(identity, composed));
+ EXPECT_TRUE(Transform::Compose(decomp).IsIdentity());
}
-TEST(XFormTest, FactorTRS) {
+TEST(XFormTest, DecomposeTranslateRotateScale) {
for (int degrees = 0; degrees < 180; ++degrees) {
// build a transformation matrix.
gfx::Transform transform;
@@ -1169,13 +1536,12 @@
transform.Scale(degrees + 1, 2 * degrees + 1);
// factor the matrix
- DecomposedTransform decomp;
- bool success = DecomposeTransform(&decomp, transform);
- EXPECT_TRUE(success);
- EXPECT_FLOAT_EQ(decomp.translate[0], degrees * 2);
- EXPECT_FLOAT_EQ(decomp.translate[1], -degrees * 3);
+ absl::optional<DecomposedTransform> decomp = transform.Decompose();
+ EXPECT_TRUE(decomp);
+ EXPECT_FLOAT_EQ(decomp->translate[0], degrees * 2);
+ EXPECT_FLOAT_EQ(decomp->translate[1], -degrees * 3);
double rotation =
- gfx::RadToDeg(std::acos(double{decomp.quaternion.w()}) * 2);
+ gfx::RadToDeg(std::acos(double{decomp->quaternion.w()}) * 2);
while (rotation < 0.0)
rotation += 360.0;
while (rotation > 360.0)
@@ -1183,26 +1549,160 @@
const float epsilon = 0.00015f;
EXPECT_NEAR(rotation, degrees, epsilon);
- EXPECT_NEAR(decomp.scale[0], degrees + 1, epsilon);
- EXPECT_NEAR(decomp.scale[1], 2 * degrees + 1, epsilon);
+ EXPECT_NEAR(decomp->scale[0], degrees + 1, epsilon);
+ EXPECT_NEAR(decomp->scale[1], 2 * degrees + 1, epsilon);
}
}
-TEST(XFormTest, DecomposeTransform) {
+TEST(XFormTest, DecomposeScaleTransform) {
for (float scale = 0.001f; scale < 2.0f; scale += 0.001f) {
- gfx::Transform transform;
- transform.Scale(scale, scale);
- EXPECT_TRUE(transform.Preserves2dAxisAlignment());
+ Transform transform = Transform::MakeScale(scale);
- DecomposedTransform decomp;
- bool success = DecomposeTransform(&decomp, transform);
- EXPECT_TRUE(success);
+ absl::optional<DecomposedTransform> decomp = transform.Decompose();
+ EXPECT_TRUE(decomp);
- gfx::Transform compose_transform = ComposeTransform(decomp);
+ Transform compose_transform = Transform::Compose(*decomp);
EXPECT_TRUE(compose_transform.Preserves2dAxisAlignment());
+ EXPECT_EQ(transform, compose_transform);
}
}
+TEST(XFormTest, Decompose2d) {
+ DecomposedTransform decomp_flip_x = *Transform::MakeScale(-2, 2).Decompose();
+ EXPECT_DECOMPOSED_TRANSFORM_EQ(
+ (DecomposedTransform{
+ {0, 0, 0}, {-2, 2, 1}, {0, 0, 0}, {0, 0, 0, 1}, {0, 0, 0, 1}}),
+ decomp_flip_x);
+
+ DecomposedTransform decomp_flip_y = *Transform::MakeScale(2, -2).Decompose();
+ EXPECT_DECOMPOSED_TRANSFORM_EQ(
+ (DecomposedTransform{
+ {0, 0, 0}, {2, -2, 1}, {0, 0, 0}, {0, 0, 0, 1}, {0, 0, 0, 1}}),
+ decomp_flip_y);
+
+ DecomposedTransform decomp_rotate_180 =
+ *Transform::Make180degRotation().Decompose();
+ EXPECT_DECOMPOSED_TRANSFORM_EQ(
+ (DecomposedTransform{
+ {0, 0, 0}, {1, 1, 1}, {0, 0, 0}, {0, 0, 0, 1}, {0, 0, 1, 0}}),
+ decomp_rotate_180);
+
+ const double kSqrt2 = std::sqrt(2);
+ const double kInvSqrt2 = 1.0 / kSqrt2;
+ DecomposedTransform decomp_rotate_90 =
+ *Transform::Make90degRotation().Decompose();
+ EXPECT_DECOMPOSED_TRANSFORM_EQ(
+ (DecomposedTransform{{0, 0, 0},
+ {1, 1, 1},
+ {0, 0, 0},
+ {0, 0, 0, 1},
+ {0, 0, kInvSqrt2, kInvSqrt2}}),
+ decomp_rotate_90);
+
+ auto translate_rotate_90 =
+ Transform::MakeTranslation(-1, 1) * Transform::Make90degRotation();
+ DecomposedTransform decomp_translate_rotate_90 =
+ *translate_rotate_90.Decompose();
+ EXPECT_DECOMPOSED_TRANSFORM_EQ(
+ (DecomposedTransform{{-1, 1, 0},
+ {1, 1, 1},
+ {0, 0, 0},
+ {0, 0, 0, 1},
+ {0, 0, kInvSqrt2, kInvSqrt2}}),
+ decomp_translate_rotate_90);
+
+ DecomposedTransform decomp_skew_rotate =
+ *Transform::Affine(1, 1, 1, 0, 0, 0).Decompose();
+ EXPECT_DECOMPOSED_TRANSFORM_EQ(
+ (DecomposedTransform{{0, 0, 0},
+ {kSqrt2, -kInvSqrt2, 1},
+ {-1, 0, 0},
+ {0, 0, 0, 1},
+ {0, 0, std::sin(base::kPiDouble / 8),
+ std::cos(base::kPiDouble / 8)}}),
+ decomp_skew_rotate);
+}
+
+double ComputeDecompRecompError(const Transform& transform) {
+ DecomposedTransform decomp = *transform.Decompose();
+ Transform composed = Transform::Compose(decomp);
+
+ float expected[16];
+ float actual[16];
+ transform.GetColMajorF(expected);
+ composed.GetColMajorF(actual);
+ double sse = 0;
+ for (int i = 0; i < 16; i++) {
+ double diff = expected[i] - actual[i];
+ sse += diff * diff;
+ }
+ return sse;
+}
+
+TEST(XFormTest, DecomposeAndCompose) {
+ // rotateZ(90deg)
+ EXPECT_NEAR(0, ComputeDecompRecompError(Transform::Make90degRotation()),
+ 1e-20);
+
+ // rotateZ(180deg)
+ // Edge case where w = 0.
+ EXPECT_EQ(0, ComputeDecompRecompError(Transform::Make180degRotation()));
+
+ // rotateX(90deg) rotateY(90deg) rotateZ(90deg)
+ // [1 0 0][ 0 0 1][0 -1 0] [0 0 1][0 -1 0] [0 0 1]
+ // [0 0 -1][ 0 1 0][1 0 0] = [1 0 0][1 0 0] = [0 -1 0]
+ // [0 1 0][-1 0 0][0 0 1] [0 1 0][0 0 1] [1 0 0]
+ // This test case leads to Gimbal lock when using Euler angles.
+ EXPECT_NEAR(0,
+ ComputeDecompRecompError(Transform::RowMajor(
+ 0, 0, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1)),
+ 1e-20);
+
+ // Quaternion matrices with 0 off-diagonal elements, and negative trace.
+ // Stress tests handling of degenerate cases in computing quaternions.
+ // Validates fix for https://crbug.com/647554.
+ EXPECT_EQ(0, ComputeDecompRecompError(Transform::Affine(1, 1, 1, 0, 0, 0)));
+ EXPECT_EQ(0, ComputeDecompRecompError(Transform::MakeScale(-1, 1)));
+ EXPECT_EQ(0, ComputeDecompRecompError(Transform::MakeScale(1, -1)));
+ Transform flip_z;
+ flip_z.Scale3d(1, 1, -1);
+ EXPECT_EQ(0, ComputeDecompRecompError(flip_z));
+
+ // The following cases exercise the branches Q_xx/yy/zz for quaternion in
+ // Matrix44::Decompose().
+ auto transform = [](double sx, double sy, double sz, int skew_r, int skew_c) {
+ Transform t;
+ t.Scale3d(sx, sy, sz);
+ t.set_rc(skew_r, skew_c, 1);
+ t.set_rc(skew_c, skew_r, 1);
+ return t;
+ };
+ EXPECT_EQ(0, ComputeDecompRecompError(transform(1, -1, -1, 0, 1)));
+ EXPECT_EQ(0, ComputeDecompRecompError(transform(1, -1, -1, 0, 2)));
+ EXPECT_EQ(0, ComputeDecompRecompError(transform(-1, 1, -1, 0, 1)));
+ EXPECT_EQ(0, ComputeDecompRecompError(transform(-1, 1, -1, 1, 2)));
+ EXPECT_EQ(0, ComputeDecompRecompError(transform(-1, -1, 1, 0, 2)));
+ EXPECT_EQ(0, ComputeDecompRecompError(transform(-1, -1, 1, 1, 2)));
+}
+
+TEST(XFormTest, IsIdentityOr2dTranslation) {
+ EXPECT_TRUE(Transform().IsIdentityOr2dTranslation());
+ EXPECT_TRUE(Transform::MakeTranslation(10, 0).IsIdentityOr2dTranslation());
+ EXPECT_TRUE(Transform::MakeTranslation(0, -20).IsIdentityOr2dTranslation());
+
+ Transform transform;
+ transform.Translate3d(0, 0, 1);
+ EXPECT_FALSE(transform.IsIdentityOr2dTranslation());
+
+ transform.MakeIdentity();
+ transform.Rotate(40);
+ EXPECT_FALSE(transform.IsIdentityOr2dTranslation());
+
+ transform.MakeIdentity();
+ transform.SkewX(30);
+ EXPECT_FALSE(transform.IsIdentityOr2dTranslation());
+}
+
TEST(XFormTest, IntegerTranslation) {
gfx::Transform transform;
EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation());
@@ -1237,48 +1737,113 @@
EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation());
}
-TEST(XFormTest, verifyMatrixInversion) {
+TEST(XFormTest, Integer2dTranslation) {
+ EXPECT_TRUE(Transform().IsIdentityOrInteger2dTranslation());
+ EXPECT_TRUE(
+ Transform::MakeTranslation(1, 2).IsIdentityOrInteger2dTranslation());
+ EXPECT_FALSE(Transform::MakeTranslation(1.00001, 2)
+ .IsIdentityOrInteger2dTranslation());
+ EXPECT_FALSE(Transform::MakeTranslation(1, 2.00002)
+ .IsIdentityOrInteger2dTranslation());
+ EXPECT_FALSE(
+ Transform::Make90degRotation().IsIdentityOrInteger2dTranslation());
+ Transform transform;
+ transform.Translate3d(1, 2, 3);
+ EXPECT_FALSE(transform.IsIdentityOrInteger2dTranslation());
+}
+
+TEST(XFormTest, Inverse) {
+ {
+ Transform identity;
+ Transform inverse_identity;
+ EXPECT_TRUE(identity.GetInverse(&inverse_identity));
+ EXPECT_EQ(identity, inverse_identity);
+ EXPECT_EQ(identity, identity.InverseOrIdentity());
+ }
+
{
// Invert a translation
- gfx::Transform translation;
+ Transform translation;
translation.Translate3d(2.0, 3.0, 4.0);
EXPECT_TRUE(translation.IsInvertible());
- gfx::Transform inverse_translation;
+ Transform inverse_translation;
bool is_invertible = translation.GetInverse(&inverse_translation);
EXPECT_TRUE(is_invertible);
- EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, -2.0f, inverse_translation);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, -3.0f, inverse_translation);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, -4.0f, inverse_translation);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_translation);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, 0.0f, -2.0f, inverse_translation);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, -3.0f, inverse_translation);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, -4.0f, inverse_translation);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_translation);
+
+ EXPECT_EQ(inverse_translation, translation.InverseOrIdentity());
+
+ // GetInverse with the parameter pointing to itself.
+ EXPECT_TRUE(translation.GetInverse(&translation));
+ EXPECT_EQ(translation, inverse_translation);
}
{
// Invert a non-uniform scale
- gfx::Transform scale;
+ Transform scale;
scale.Scale3d(4.0, 10.0, 100.0);
EXPECT_TRUE(scale.IsInvertible());
- gfx::Transform inverse_scale;
+ Transform inverse_scale;
bool is_invertible = scale.GetInverse(&inverse_scale);
EXPECT_TRUE(is_invertible);
- EXPECT_ROW1_EQ(0.25f, 0.0f, 0.0f, 0.0f, inverse_scale);
- EXPECT_ROW2_EQ(0.0f, 0.1f, 0.0f, 0.0f, inverse_scale);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 0.01f, 0.0f, inverse_scale);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_scale);
+ EXPECT_ROW0_EQ(0.25f, 0.0f, 0.0f, 0.0f, inverse_scale);
+ EXPECT_ROW1_EQ(0.0f, 0.1f, 0.0f, 0.0f, inverse_scale);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 0.01f, 0.0f, inverse_scale);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_scale);
+
+ EXPECT_EQ(inverse_scale, scale.InverseOrIdentity());
+ }
+
+ {
+ Transform m1;
+ m1.Translate(10, 20);
+ m1.Rotate(30);
+ Transform m2;
+ m2.Rotate(-30);
+ m2.Translate(-10, -20);
+ Transform inverse_m1, inverse_m2;
+ EXPECT_TRUE(m1.GetInverse(&inverse_m1));
+ EXPECT_TRUE(m2.GetInverse(&inverse_m2));
+ EXPECT_TRUE(inverse_m1.Is2dTransform());
+ EXPECT_TRUE(inverse_m2.Is2dTransform());
+ EXPECT_TRANSFORM_NEAR(m1, inverse_m2, 1e-6);
+ EXPECT_TRANSFORM_NEAR(m2, inverse_m1, 1e-6);
+ }
+
+ {
+ Transform m1;
+ m1.RotateAboutZAxis(-30);
+ m1.RotateAboutYAxis(10);
+ m1.RotateAboutXAxis(20);
+ m1.ApplyPerspectiveDepth(100);
+ Transform m2;
+ m2.ApplyPerspectiveDepth(-100);
+ m2.RotateAboutXAxis(-20);
+ m2.RotateAboutYAxis(-10);
+ m2.RotateAboutZAxis(30);
+ Transform inverse_m1, inverse_m2;
+ EXPECT_TRUE(m1.GetInverse(&inverse_m1));
+ EXPECT_TRUE(m2.GetInverse(&inverse_m2));
+ EXPECT_TRANSFORM_NEAR(m1, inverse_m2, 1e-6);
+ EXPECT_TRANSFORM_NEAR(m2, inverse_m1, 1e-6);
}
{
// Try to invert a matrix that is not invertible.
// The inverse() function should reset the output matrix to identity.
- gfx::Transform uninvertible;
- uninvertible.matrix().set(0, 0, 0.f);
- uninvertible.matrix().set(1, 1, 0.f);
- uninvertible.matrix().set(2, 2, 0.f);
- uninvertible.matrix().set(3, 3, 0.f);
+ Transform uninvertible;
+ uninvertible.set_rc(0, 0, 0.f);
+ uninvertible.set_rc(1, 1, 0.f);
+ uninvertible.set_rc(2, 2, 0.f);
+ uninvertible.set_rc(3, 3, 0.f);
EXPECT_FALSE(uninvertible.IsInvertible());
- gfx::Transform inverse_of_uninvertible;
+ Transform inverse_of_uninvertible;
// Add a scale just to more easily ensure that inverse_of_uninvertible is
// reset to identity.
@@ -1287,10 +1852,12 @@
bool is_invertible = uninvertible.GetInverse(&inverse_of_uninvertible);
EXPECT_FALSE(is_invertible);
EXPECT_TRUE(inverse_of_uninvertible.IsIdentity());
- EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, inverse_of_uninvertible);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, inverse_of_uninvertible);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, inverse_of_uninvertible);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_of_uninvertible);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, 0.0f, 0.0f, inverse_of_uninvertible);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 0.0f, inverse_of_uninvertible);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, inverse_of_uninvertible);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, inverse_of_uninvertible);
+
+ EXPECT_EQ(inverse_of_uninvertible, uninvertible.InverseOrIdentity());
}
}
@@ -1312,6 +1879,18 @@
transform.MakeIdentity();
transform.RotateAboutYAxis(90.0);
EXPECT_FALSE(transform.IsBackFaceVisible());
+
+ // 2d scale doesn't affect backface visibility.
+ auto check_scale = [&](float scale_x, float scale_y) {
+ transform = Transform::MakeScale(scale_x, scale_y);
+ EXPECT_FALSE(transform.IsBackFaceVisible());
+ transform.EnsureFullMatrixForTesting();
+ EXPECT_FALSE(transform.IsBackFaceVisible());
+ };
+ check_scale(1, 2);
+ check_scale(-1, 2);
+ check_scale(1, -2);
+ check_scale(-1, -2);
}
TEST(XFormTest, verifyBackfaceVisibilityForPerspective) {
@@ -1358,176 +1937,227 @@
}
TEST(XFormTest, verifyDefaultConstructorCreatesIdentityMatrix) {
- Transform A;
- EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ constexpr Transform A;
+ STATIC_ROW0_EQ(1.0, 0.0, 0.0, 0.0, A);
+ STATIC_ROW1_EQ(0.0, 1.0, 0.0, 0.0, A);
+ STATIC_ROW2_EQ(0.0, 0.0, 1.0, 0.0, A);
+ STATIC_ROW3_EQ(0.0, 0.0, 0.0, 1.0, A);
EXPECT_TRUE(A.IsIdentity());
}
TEST(XFormTest, verifyCopyConstructor) {
- Transform A;
- InitializeTestMatrix(&A);
+ Transform A = GetTestMatrix1();
// Copy constructor should produce exact same elements as matrix A.
Transform B(A);
- EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
- EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
- EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
- EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
+ EXPECT_EQ(A, B);
+ EXPECT_ROW0_EQ(10.0, 14.0, 18.0, 22.0, B);
+ EXPECT_ROW1_EQ(11.0, 15.0, 19.0, 23.0, B);
+ EXPECT_ROW2_EQ(12.0, 16.0, 20.0, 24.0, B);
+ EXPECT_ROW3_EQ(13.0, 17.0, 21.0, 25.0, B);
}
-TEST(XFormTest, verifyConstructorFor16Elements) {
- Transform transform(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0,
- 12.0, 13.0, 14.0, 15.0, 16.0);
+// ColMajor() and RowMajor() are tested in GetTestMatrix1() and
+// GetTestTransform2().
- EXPECT_ROW1_EQ(1.0f, 2.0f, 3.0f, 4.0f, transform);
- EXPECT_ROW2_EQ(5.0f, 6.0f, 7.0f, 8.0f, transform);
- EXPECT_ROW3_EQ(9.0f, 10.0f, 11.0f, 12.0f, transform);
- EXPECT_ROW4_EQ(13.0f, 14.0f, 15.0f, 16.0f, transform);
+TEST(XFormTest, GetColMajor) {
+ auto transform = GetTestMatrix1();
+
+ double data[16];
+ transform.GetColMajor(data);
+ for (int i = 0; i < 16; i++) {
+ EXPECT_EQ(i + 10.0, data[i]);
+ EXPECT_EQ(data[i], transform.ColMajorData(i));
+ }
+ EXPECT_EQ(transform, Transform::ColMajor(data));
}
-TEST(XFormTest, verifyConstructorFor2dElements) {
- Transform transform(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
+TEST(XFormTest, Affine) {
+ constexpr auto transform = Transform::Affine(2.0, 3., 4.0, 5.0, 6.0, 7.0);
+ STATIC_ROW0_EQ(2.0, 4.0, 0.0, 6.0, transform);
+ STATIC_ROW1_EQ(3.0, 5.0, 0.0, 7.0, transform);
+ STATIC_ROW2_EQ(0.0, 0.0, 1.0, 0.0, transform);
+ STATIC_ROW3_EQ(0.0, 0.0, 0.0, 1.0, transform);
+}
- EXPECT_ROW1_EQ(1.0f, 2.0f, 0.0f, 5.0f, transform);
- EXPECT_ROW2_EQ(3.0f, 4.0f, 0.0f, 6.0f, transform);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, transform);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, transform);
+TEST(XFormTest, MakeTranslation) {
+ constexpr auto t = Transform::MakeTranslation(3.5, 4.75);
+ STATIC_ROW0_EQ(1.0, 0.0, 0.0, 3.5, t);
+ STATIC_ROW1_EQ(0.0, 1.0, 0.0, 4.75, t);
+ STATIC_ROW2_EQ(0.0, 0.0, 1.0, 0.0, t);
+ STATIC_ROW3_EQ(0.0, 0.0, 0.0, 1.0, t);
+}
+
+TEST(XFormTest, MakeScale) {
+ constexpr auto s = Transform::MakeScale(3.5, 4.75);
+ STATIC_ROW0_EQ(3.5, 0.0, 0.0, 0, s);
+ STATIC_ROW1_EQ(0.0, 4.75, 0.0, 0, s);
+ STATIC_ROW2_EQ(0.0, 0.0, 1.0, 0.0, s);
+ STATIC_ROW3_EQ(0.0, 0.0, 0.0, 1.0, s);
+}
+
+TEST(XFormTest, MakeRotation) {
+ constexpr auto r1 = Transform::Make90degRotation();
+ STATIC_ROW0_EQ(0.0, -1.0, 0.0, 0, r1);
+ STATIC_ROW1_EQ(1.0, 0.0, 0.0, 0, r1);
+ STATIC_ROW2_EQ(0.0, 0.0, 1.0, 0.0, r1);
+ STATIC_ROW3_EQ(0.0, 0.0, 0.0, 1.0, r1);
+
+ constexpr auto r2 = Transform::Make180degRotation();
+ STATIC_ROW0_EQ(-1.0, 0.0, 0.0, 0, r2);
+ STATIC_ROW1_EQ(0.0, -1.0, 0.0, 0, r2);
+ STATIC_ROW2_EQ(0.0, 0.0, 1.0, 0.0, r2);
+ STATIC_ROW3_EQ(0.0, 0.0, 0.0, 1.0, r2);
+
+ constexpr auto r3 = Transform::Make270degRotation();
+ STATIC_ROW0_EQ(0.0, 1.0, 0.0, 0, r3);
+ STATIC_ROW1_EQ(-1.0, 0.0, 0.0, 0, r3);
+ STATIC_ROW2_EQ(0.0, 0.0, 1.0, 0.0, r3);
+ STATIC_ROW3_EQ(0.0, 0.0, 0.0, 1.0, r3);
+}
+
+TEST(XFormTest, ColMajorF) {
+ float data[] = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17};
+ auto transform = Transform::ColMajorF(data);
+
+ EXPECT_ROW0_EQ(2.0, 6.0, 10.0, 14.0, transform);
+ EXPECT_ROW1_EQ(3.0, 7.0, 11.0, 15.0, transform);
+ EXPECT_ROW2_EQ(4.0, 8.0, 12.0, 16.0, transform);
+ EXPECT_ROW3_EQ(5.0, 9.0, 13.0, 17.0, transform);
+
+ float data1[16];
+ transform.GetColMajorF(data1);
+ for (int i = 0; i < 16; i++)
+ EXPECT_EQ(data1[i], data[i]);
+ EXPECT_EQ(transform, Transform::ColMajorF(data1));
+}
+
+TEST(XFormTest, FromQuaternion) {
+ Transform t(Quaternion(1, 2, 3, 4));
+ EXPECT_ROW0_EQ(-25.f, -20.f, 22.f, 0.f, t);
+ EXPECT_ROW1_EQ(28.f, -19.f, 4.f, 0.f, t);
+ EXPECT_ROW2_EQ(-10.f, 20.f, -9.f, 0.f, t);
+ EXPECT_ROW3_EQ(0.f, 0.f, 0.f, 1.f, t);
}
TEST(XFormTest, verifyAssignmentOperator) {
- Transform A;
- InitializeTestMatrix(&A);
- Transform B;
- InitializeTestMatrix2(&B);
- Transform C;
- InitializeTestMatrix2(&C);
+ Transform A = GetTestMatrix1();
+ Transform B = GetTestMatrix2();
+ Transform C = GetTestMatrix2();
C = B = A;
// Both B and C should now have been re-assigned to the value of A.
- EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
- EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
- EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
- EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
+ EXPECT_ROW0_EQ(10.0f, 14.0f, 18.0f, 22.0f, B);
+ EXPECT_ROW1_EQ(11.0f, 15.0f, 19.0f, 23.0f, B);
+ EXPECT_ROW2_EQ(12.0f, 16.0f, 20.0f, 24.0f, B);
+ EXPECT_ROW3_EQ(13.0f, 17.0f, 21.0f, 25.0f, B);
- EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, C);
- EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, C);
- EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, C);
- EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, C);
+ EXPECT_ROW0_EQ(10.0f, 14.0f, 18.0f, 22.0f, C);
+ EXPECT_ROW1_EQ(11.0f, 15.0f, 19.0f, 23.0f, C);
+ EXPECT_ROW2_EQ(12.0f, 16.0f, 20.0f, 24.0f, C);
+ EXPECT_ROW3_EQ(13.0f, 17.0f, 21.0f, 25.0f, C);
}
TEST(XFormTest, verifyEqualsBooleanOperator) {
- Transform A;
- InitializeTestMatrix(&A);
-
- Transform B;
- InitializeTestMatrix(&B);
+ Transform A = GetTestMatrix1();
+ Transform B = GetTestMatrix1();
EXPECT_TRUE(A == B);
// Modifying multiple elements should cause equals operator to return false.
- Transform C;
- InitializeTestMatrix2(&C);
+ Transform C = GetTestMatrix2();
EXPECT_FALSE(A == C);
// Modifying any one individual element should cause equals operator to
// return false.
Transform D;
D = A;
- D.matrix().set(0, 0, 0.f);
+ D.set_rc(0, 0, 0.f);
EXPECT_FALSE(A == D);
D = A;
- D.matrix().set(1, 0, 0.f);
+ D.set_rc(1, 0, 0.f);
EXPECT_FALSE(A == D);
D = A;
- D.matrix().set(2, 0, 0.f);
+ D.set_rc(2, 0, 0.f);
EXPECT_FALSE(A == D);
D = A;
- D.matrix().set(3, 0, 0.f);
+ D.set_rc(3, 0, 0.f);
EXPECT_FALSE(A == D);
D = A;
- D.matrix().set(0, 1, 0.f);
+ D.set_rc(0, 1, 0.f);
EXPECT_FALSE(A == D);
D = A;
- D.matrix().set(1, 1, 0.f);
+ D.set_rc(1, 1, 0.f);
EXPECT_FALSE(A == D);
D = A;
- D.matrix().set(2, 1, 0.f);
+ D.set_rc(2, 1, 0.f);
EXPECT_FALSE(A == D);
D = A;
- D.matrix().set(3, 1, 0.f);
+ D.set_rc(3, 1, 0.f);
EXPECT_FALSE(A == D);
D = A;
- D.matrix().set(0, 2, 0.f);
+ D.set_rc(0, 2, 0.f);
EXPECT_FALSE(A == D);
D = A;
- D.matrix().set(1, 2, 0.f);
+ D.set_rc(1, 2, 0.f);
EXPECT_FALSE(A == D);
D = A;
- D.matrix().set(2, 2, 0.f);
+ D.set_rc(2, 2, 0.f);
EXPECT_FALSE(A == D);
D = A;
- D.matrix().set(3, 2, 0.f);
+ D.set_rc(3, 2, 0.f);
EXPECT_FALSE(A == D);
D = A;
- D.matrix().set(0, 3, 0.f);
+ D.set_rc(0, 3, 0.f);
EXPECT_FALSE(A == D);
D = A;
- D.matrix().set(1, 3, 0.f);
+ D.set_rc(1, 3, 0.f);
EXPECT_FALSE(A == D);
D = A;
- D.matrix().set(2, 3, 0.f);
+ D.set_rc(2, 3, 0.f);
EXPECT_FALSE(A == D);
D = A;
- D.matrix().set(3, 3, 0.f);
+ D.set_rc(3, 3, 0.f);
EXPECT_FALSE(A == D);
}
TEST(XFormTest, verifyMultiplyOperator) {
- Transform A;
- InitializeTestMatrix(&A);
-
- Transform B;
- InitializeTestMatrix2(&B);
+ Transform A = GetTestMatrix1();
+ Transform B = GetTestMatrix2();
Transform C = A * B;
- EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, C);
- EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, C);
- EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, C);
- EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, C);
+ EXPECT_ROW0_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, C);
+ EXPECT_ROW1_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, C);
+ EXPECT_ROW2_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, C);
+ EXPECT_ROW3_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, C);
// Just an additional sanity check; matrix multiplication is not commutative.
EXPECT_FALSE(A * B == B * A);
}
TEST(XFormTest, verifyMultiplyAndAssignOperator) {
- Transform A;
- InitializeTestMatrix(&A);
-
- Transform B;
- InitializeTestMatrix2(&B);
+ Transform A = GetTestMatrix1();
+ Transform B = GetTestMatrix2();
A *= B;
- EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
- EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
- EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
- EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
+ EXPECT_ROW0_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
+ EXPECT_ROW1_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
+ EXPECT_ROW2_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
+ EXPECT_ROW3_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
// Just an additional sanity check; matrix multiplication is not commutative.
Transform C = A;
@@ -1537,151 +2167,221 @@
EXPECT_FALSE(C == D);
}
-TEST(XFormTest, verifyMatrixMultiplication) {
- Transform A;
- InitializeTestMatrix(&A);
+TEST(XFormTest, PreConcat) {
+ Transform A = GetTestMatrix1();
+ Transform B = GetTestMatrix2();
- Transform B;
- InitializeTestMatrix2(&B);
-
- A.PreconcatTransform(B);
- EXPECT_ROW1_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
- EXPECT_ROW2_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
- EXPECT_ROW3_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
- EXPECT_ROW4_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
+ A.PreConcat(B);
+ EXPECT_ROW0_EQ(2036.0f, 2292.0f, 2548.0f, 2804.0f, A);
+ EXPECT_ROW1_EQ(2162.0f, 2434.0f, 2706.0f, 2978.0f, A);
+ EXPECT_ROW2_EQ(2288.0f, 2576.0f, 2864.0f, 3152.0f, A);
+ EXPECT_ROW3_EQ(2414.0f, 2718.0f, 3022.0f, 3326.0f, A);
}
TEST(XFormTest, verifyMakeIdentiy) {
- Transform A;
- InitializeTestMatrix(&A);
+ Transform A = GetTestMatrix1();
A.MakeIdentity();
- EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
EXPECT_TRUE(A.IsIdentity());
}
TEST(XFormTest, verifyTranslate) {
Transform A;
A.Translate(2.0, 3.0);
- EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
// Verify that Translate() post-multiplies the existing matrix.
A.MakeIdentity();
A.Scale(5.0, 5.0);
A.Translate(2.0, 3.0);
- EXPECT_ROW1_EQ(5.0f, 0.0f, 0.0f, 10.0f, A);
- EXPECT_ROW2_EQ(0.0f, 5.0f, 0.0f, 15.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(5.0f, 0.0f, 0.0f, 10.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 5.0f, 0.0f, 15.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+
+ Transform B;
+ B.Scale(5.0, 5.0);
+ B.Translate(Vector2dF(2.0f, 3.0f));
+ EXPECT_EQ(A, B);
+}
+
+TEST(XFormTest, verifyPostTranslate) {
+ Transform A;
+ A.PostTranslate(2.0, 3.0);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+
+ // Verify that PostTranslate() pre-multiplies the existing matrix.
+ A.MakeIdentity();
+ A.Scale(5.0, 5.0);
+ A.PostTranslate(2.0, 3.0);
+ EXPECT_ROW0_EQ(5.0f, 0.0f, 0.0f, 2.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 5.0f, 0.0f, 3.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+
+ Transform B;
+ B.Scale(5.0, 5.0);
+ B.PostTranslate(Vector2dF(2.0f, 3.0f));
+ EXPECT_EQ(A, B);
}
TEST(XFormTest, verifyTranslate3d) {
Transform A;
A.Translate3d(2.0, 3.0, 4.0);
- EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
// Verify that Translate3d() post-multiplies the existing matrix.
A.MakeIdentity();
A.Scale3d(6.0, 7.0, 8.0);
A.Translate3d(2.0, 3.0, 4.0);
- EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 12.0f, A);
- EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 21.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 32.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(6.0f, 0.0f, 0.0f, 12.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 7.0f, 0.0f, 21.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 8.0f, 32.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+
+ Transform B;
+ B.Scale3d(6.0, 7.0, 8.0);
+ B.Translate3d(Vector3dF(2.0f, 3.0f, 4.0f));
+ EXPECT_EQ(A, B);
+}
+
+TEST(XFormTest, verifyPostTranslate3d) {
+ Transform A;
+ A.PostTranslate3d(2.0, 3.0, 4.0);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, 0.0f, 2.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 3.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+
+ // Verify that PostTranslate3d() pre-multiplies the existing matrix.
+ A.MakeIdentity();
+ A.Scale3d(6.0, 7.0, 8.0);
+ A.PostTranslate3d(2.0, 3.0, 4.0);
+ EXPECT_ROW0_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 8.0f, 4.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+
+ Transform B;
+ B.Scale3d(6.0, 7.0, 8.0);
+ B.PostTranslate3d(Vector3dF(2.0f, 3.0f, 4.0f));
+ EXPECT_EQ(A, B);
}
TEST(XFormTest, verifyScale) {
Transform A;
A.Scale(6.0, 7.0);
- EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
- EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
// Verify that Scale() post-multiplies the existing matrix.
A.MakeIdentity();
A.Translate3d(2.0, 3.0, 4.0);
A.Scale(6.0, 7.0);
- EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
- EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 4.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
}
TEST(XFormTest, verifyScale3d) {
Transform A;
A.Scale3d(6.0, 7.0, 8.0);
- EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
- EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
// Verify that scale3d() post-multiplies the existing matrix.
A.MakeIdentity();
A.Translate3d(2.0, 3.0, 4.0);
A.Scale3d(6.0, 7.0, 8.0);
- EXPECT_ROW1_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
- EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 4.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(6.0f, 0.0f, 0.0f, 2.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 7.0f, 0.0f, 3.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 8.0f, 4.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
}
-TEST(XFormTest, verifyRotate) {
+TEST(XFormTest, verifyPostScale3d) {
+ Transform A;
+ A.PostScale3d(6.0, 7.0, 8.0);
+ EXPECT_ROW0_EQ(6.0f, 0.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+
+ // Verify that PostScale3d() pre-multiplies the existing matrix.
+ A.MakeIdentity();
+ A.Translate3d(2.0, 3.0, 4.0);
+ A.PostScale3d(6.0, 7.0, 8.0);
+ EXPECT_ROW0_EQ(6.0f, 0.0f, 0.0f, 12.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 7.0f, 0.0f, 21.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 8.0f, 32.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+}
+
+TEST(XFormTest, Rotate) {
Transform A;
A.Rotate(90.0);
- EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(0.0, -1.0, 0.0, 0.0, A);
+ EXPECT_ROW1_EQ(1.0, 0.0, 0.0, 0.0, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
// Verify that Rotate() post-multiplies the existing matrix.
A.MakeIdentity();
A.Scale3d(6.0, 7.0, 8.0);
A.Rotate(90.0);
- EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(0.0, -6.0, 0.0, 0.0, A);
+ EXPECT_ROW1_EQ(7.0, 0.0, 0.0, 0.0, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
}
-TEST(XFormTest, verifyRotateAboutXAxis) {
+TEST(XFormTest, RotateAboutXAxis) {
Transform A;
double sin45 = 0.5 * sqrt(2.0);
double cos45 = sin45;
A.MakeIdentity();
A.RotateAboutXAxis(90.0);
- EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
- EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW1_EQ(0.0, 0.0, -1.0, 0.0, A);
+ EXPECT_ROW2_EQ(0.0, 1.0, 0.0, 0.0, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
A.MakeIdentity();
A.RotateAboutXAxis(45.0);
- EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
- EXPECT_ROW2_NEAR(0.0, cos45, -sin45, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW3_NEAR(0.0, sin45, cos45, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW1_NEAR(0.0, cos45, -sin45, 0.0, A, kErrorThreshold);
+ EXPECT_ROW2_NEAR(0.0, sin45, cos45, 0.0, A, kErrorThreshold);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
// Verify that RotateAboutXAxis(angle) post-multiplies the existing matrix.
A.MakeIdentity();
A.Scale3d(6.0, 7.0, 8.0);
A.RotateAboutXAxis(90.0);
- EXPECT_ROW1_NEAR(6.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(0.0, 0.0, -7.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW3_NEAR(0.0, 8.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(6.0, 0.0, 0.0, 0.0, A);
+ EXPECT_ROW1_EQ(0.0, 0.0, -7.0, 0.0, A);
+ EXPECT_ROW2_EQ(0.0, 8.0, 0.0, 0.0, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
}
-TEST(XFormTest, verifyRotateAboutYAxis) {
+TEST(XFormTest, RotateAboutYAxis) {
Transform A;
double sin45 = 0.5 * sqrt(2.0);
double cos45 = sin45;
@@ -1690,106 +2390,106 @@
// about x axis or z axis.
A.MakeIdentity();
A.RotateAboutYAxis(90.0);
- EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
- EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(0.0, 0.0, 1.0, 0.0, A);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW2_EQ(-1.0, 0.0, 0.0, 0.0, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
A.MakeIdentity();
A.RotateAboutYAxis(45.0);
- EXPECT_ROW1_NEAR(cos45, 0.0, sin45, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
- EXPECT_ROW3_NEAR(-sin45, 0.0, cos45, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_NEAR(cos45, 0.0, sin45, 0.0, A, kErrorThreshold);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW2_NEAR(-sin45, 0.0, cos45, 0.0, A, kErrorThreshold);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
// Verify that RotateAboutYAxis(angle) post-multiplies the existing matrix.
A.MakeIdentity();
A.Scale3d(6.0, 7.0, 8.0);
A.RotateAboutYAxis(90.0);
- EXPECT_ROW1_NEAR(0.0, 0.0, 6.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(0.0, 7.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW3_NEAR(-8.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(0.0, 0.0, 6.0, 0.0, A);
+ EXPECT_ROW1_EQ(0.0, 7.0, 0.0, 0.0, A);
+ EXPECT_ROW2_EQ(-8.0, 0.0, 0.0, 0.0, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
}
-TEST(XFormTest, verifyRotateAboutZAxis) {
+TEST(XFormTest, RotateAboutZAxis) {
Transform A;
double sin45 = 0.5 * sqrt(2.0);
double cos45 = sin45;
A.MakeIdentity();
A.RotateAboutZAxis(90.0);
- EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(0.0, -1.0, 0.0, 0.0, A);
+ EXPECT_ROW1_EQ(1.0, 0.0, 0.0, 0.0, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
A.MakeIdentity();
A.RotateAboutZAxis(45.0);
- EXPECT_ROW1_NEAR(cos45, -sin45, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(sin45, cos45, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_NEAR(cos45, -sin45, 0.0, 0.0, A, kErrorThreshold);
+ EXPECT_ROW1_NEAR(sin45, cos45, 0.0, 0.0, A, kErrorThreshold);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
// Verify that RotateAboutZAxis(angle) post-multiplies the existing matrix.
A.MakeIdentity();
A.Scale3d(6.0, 7.0, 8.0);
A.RotateAboutZAxis(90.0);
- EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(0.0, -6.0, 0.0, 0.0, A);
+ EXPECT_ROW1_EQ(7.0, 0.0, 0.0, 0.0, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
}
-TEST(XFormTest, verifyRotateAboutForAlignedAxes) {
+TEST(XFormTest, RotateAboutForAlignedAxes) {
Transform A;
// Check rotation about z-axis
A.MakeIdentity();
A.RotateAbout(Vector3dF(0.0, 0.0, 1.0), 90.0);
- EXPECT_ROW1_NEAR(0.0, -1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(0.0, -1.0, 0.0, 0.0, A);
+ EXPECT_ROW1_EQ(1.0, 0.0, 0.0, 0.0, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
// Check rotation about x-axis
A.MakeIdentity();
A.RotateAbout(Vector3dF(1.0, 0.0, 0.0), 90.0);
- EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
- EXPECT_ROW2_NEAR(0.0, 0.0, -1.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW3_NEAR(0.0, 1.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW1_EQ(0.0, 0.0, -1.0, 0.0, A);
+ EXPECT_ROW2_EQ(0.0, 1.0, 0.0, 0.0, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
// Check rotation about y-axis. Note carefully, the expected pattern is
// inverted compared to rotating about x axis or z axis.
A.MakeIdentity();
A.RotateAbout(Vector3dF(0.0, 1.0, 0.0), 90.0);
- EXPECT_ROW1_NEAR(0.0, 0.0, 1.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
- EXPECT_ROW3_NEAR(-1.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(0.0, 0.0, 1.0, 0.0, A);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW2_EQ(-1.0, 0.0, 0.0, 0.0, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
// Verify that rotate3d(axis, angle) post-multiplies the existing matrix.
A.MakeIdentity();
A.Scale3d(6.0, 7.0, 8.0);
A.RotateAboutZAxis(90.0);
- EXPECT_ROW1_NEAR(0.0, -6.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(7.0, 0.0, 0.0, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(0.0, -6.0, 0.0, 0.0, A);
+ EXPECT_ROW1_EQ(7.0, 0.0, 0.0, 0.0, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
}
TEST(XFormTest, verifyRotateAboutForArbitraryAxis) {
// Check rotation about an arbitrary non-axis-aligned vector.
Transform A;
A.RotateAbout(Vector3dF(1.0, 1.0, 1.0), 90.0);
- EXPECT_ROW1_NEAR(0.3333333333333334258519187, -0.2440169358562924717404030,
- 0.9106836025229592124219380, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW2_NEAR(0.9106836025229592124219380, 0.3333333333333334258519187,
- -0.2440169358562924717404030, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW3_NEAR(-0.2440169358562924717404030, 0.9106836025229592124219380,
- 0.3333333333333334258519187, 0.0, A, ERROR_THRESHOLD);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_NEAR(0.3333333333333334258519187, -0.2440169358562924717404030,
+ 0.9106836025229592124219380, 0.0, A, kErrorThreshold);
+ EXPECT_ROW1_NEAR(0.9106836025229592124219380, 0.3333333333333334258519187,
+ -0.2440169358562924717404030, 0.0, A, kErrorThreshold);
+ EXPECT_ROW2_NEAR(-0.2440169358562924717404030, 0.9106836025229592124219380,
+ 0.3333333333333334258519187, 0.0, A, kErrorThreshold);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
}
TEST(XFormTest, verifyRotateAboutForDegenerateAxis) {
@@ -1801,32 +2501,32 @@
// Verify that A remains unchanged.
EXPECT_TRUE(A.IsIdentity());
- InitializeTestMatrix(&A);
+ A = GetTestMatrix1();
A.RotateAbout(Vector3dF(0.0, 0.0, 0.0), 35.0);
// Verify that A remains unchanged.
- EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, A);
- EXPECT_ROW2_EQ(11.0f, 15.0f, 19.0f, 23.0f, A);
- EXPECT_ROW3_EQ(12.0f, 16.0f, 20.0f, 24.0f, A);
- EXPECT_ROW4_EQ(13.0f, 17.0f, 21.0f, 25.0f, A);
+ EXPECT_ROW0_EQ(10.0f, 14.0f, 18.0f, 22.0f, A);
+ EXPECT_ROW1_EQ(11.0f, 15.0f, 19.0f, 23.0f, A);
+ EXPECT_ROW2_EQ(12.0f, 16.0f, 20.0f, 24.0f, A);
+ EXPECT_ROW3_EQ(13.0f, 17.0f, 21.0f, 25.0f, A);
}
TEST(XFormTest, verifySkew) {
// Test a skew along X axis only
Transform A;
A.Skew(45.0, 0.0);
- EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
// Test a skew along Y axis only
A.MakeIdentity();
A.Skew(0.0, 45.0);
- EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
- EXPECT_ROW2_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
// Verify that skew() post-multiplies the existing matrix. Row 1, column 2,
// would incorrectly have value "7" if the matrix is pre-multiplied instead
@@ -1834,36 +2534,36 @@
A.MakeIdentity();
A.Scale3d(6.0, 7.0, 8.0);
A.Skew(45.0, 0.0);
- EXPECT_ROW1_EQ(6.0f, 6.0f, 0.0f, 0.0f, A);
- EXPECT_ROW2_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(6.0f, 6.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 7.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 8.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
// Test a skew along X and Y axes both
A.MakeIdentity();
A.Skew(45.0, 45.0);
+ EXPECT_ROW0_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
EXPECT_ROW1_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
- EXPECT_ROW2_EQ(1.0f, 1.0f, 0.0f, 0.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, 0.0f, 1.0f, A);
}
TEST(XFormTest, verifyPerspectiveDepth) {
Transform A;
A.ApplyPerspectiveDepth(1.0);
- EXPECT_ROW1_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
- EXPECT_ROW2_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, 0.0f, 0.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
// Verify that PerspectiveDepth() post-multiplies the existing matrix.
A.MakeIdentity();
A.Translate3d(2.0, 3.0, 4.0);
A.ApplyPerspectiveDepth(1.0);
- EXPECT_ROW1_EQ(1.0f, 0.0f, -2.0f, 2.0f, A);
- EXPECT_ROW2_EQ(0.0f, 1.0f, -3.0f, 3.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, -3.0f, 4.0f, A);
- EXPECT_ROW4_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
+ EXPECT_ROW0_EQ(1.0f, 0.0f, -2.0f, 2.0f, A);
+ EXPECT_ROW1_EQ(0.0f, 1.0f, -3.0f, 3.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, -3.0f, 4.0f, A);
+ EXPECT_ROW3_EQ(0.0f, 0.0f, -1.0f, 1.0f, A);
}
TEST(XFormTest, verifyHasPerspective) {
@@ -1876,23 +2576,23 @@
EXPECT_FALSE(A.HasPerspective());
A.MakeIdentity();
- A.matrix().set(3, 0, -1.f);
+ A.set_rc(3, 0, -1.f);
EXPECT_TRUE(A.HasPerspective());
A.MakeIdentity();
- A.matrix().set(3, 1, -1.f);
+ A.set_rc(3, 1, -1.f);
EXPECT_TRUE(A.HasPerspective());
A.MakeIdentity();
- A.matrix().set(3, 2, -0.3f);
+ A.set_rc(3, 2, -0.3f);
EXPECT_TRUE(A.HasPerspective());
A.MakeIdentity();
- A.matrix().set(3, 3, 0.5f);
+ A.set_rc(3, 3, 0.5f);
EXPECT_TRUE(A.HasPerspective());
A.MakeIdentity();
- A.matrix().set(3, 3, 0.f);
+ A.set_rc(3, 3, 0.f);
EXPECT_TRUE(A.HasPerspective());
}
@@ -1929,41 +2629,45 @@
A.ApplyPerspectiveDepth(1.0);
EXPECT_TRUE(A.IsInvertible());
- // A "pure" perspective matrix derived by similar triangles, with m44() set
+ // A "pure" perspective matrix derived by similar triangles, with rc(3, 3) set
// to zero (i.e. camera positioned at the origin), is not invertible.
A.MakeIdentity();
A.ApplyPerspectiveDepth(1.0);
- A.matrix().set(3, 3, 0.f);
+ A.set_rc(3, 3, 0.f);
EXPECT_FALSE(A.IsInvertible());
// Adding more to a non-invertible matrix will not make it invertible in the
// general case.
A.MakeIdentity();
A.ApplyPerspectiveDepth(1.0);
- A.matrix().set(3, 3, 0.f);
- A.Scale3d(6.0, 7.0, 8.0);
- A.RotateAboutXAxis(10.0);
- A.RotateAboutYAxis(20.0);
- A.RotateAboutZAxis(30.0);
- A.Translate3d(6.0, 7.0, 8.0);
-#if !defined(ARCH_CPU_ARM_FAMILY)
- // TODO(enne): Make this pass on ARM, https://crbug.com/662558
+ A.set_rc(3, 3, 0.f);
EXPECT_FALSE(A.IsInvertible());
-#endif
+ A.Scale3d(6.0, 7.0, 8.0);
+ EXPECT_FALSE(A.IsInvertible());
+ A.RotateAboutXAxis(10.0);
+ EXPECT_FALSE(A.IsInvertible());
+ A.RotateAboutYAxis(20.0);
+ EXPECT_FALSE(A.IsInvertible());
+ A.RotateAboutZAxis(30.0);
+ EXPECT_FALSE(A.IsInvertible());
+ A.Translate3d(6.0, 7.0, 8.0);
+ if (A.IsInvertible()) {
+ // Due to some computation errors, now A may become invertible with a tiny
+ // determinant.
+ EXPECT_NEAR(A.Determinant(), 0.0, 1e-12);
+ }
// A degenerate matrix of all zeros is not invertible.
A.MakeIdentity();
- A.matrix().set(0, 0, 0.f);
- A.matrix().set(1, 1, 0.f);
- A.matrix().set(2, 2, 0.f);
- A.matrix().set(3, 3, 0.f);
+ A.set_rc(0, 0, 0.f);
+ A.set_rc(1, 1, 0.f);
+ A.set_rc(2, 2, 0.f);
+ A.set_rc(3, 3, 0.f);
EXPECT_FALSE(A.IsInvertible());
}
TEST(XFormTest, verifyIsIdentity) {
- Transform A;
-
- InitializeTestMatrix(&A);
+ Transform A = GetTestMatrix1();
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
@@ -1972,74 +2676,72 @@
// Modifying any one individual element should cause the matrix to no longer
// be identity.
A.MakeIdentity();
- A.matrix().set(0, 0, 2.f);
+ A.set_rc(0, 0, 2.f);
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
- A.matrix().set(1, 0, 2.f);
+ A.set_rc(1, 0, 2.f);
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
- A.matrix().set(2, 0, 2.f);
+ A.set_rc(2, 0, 2.f);
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
- A.matrix().set(3, 0, 2.f);
+ A.set_rc(3, 0, 2.f);
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
- A.matrix().set(0, 1, 2.f);
+ A.set_rc(0, 1, 2.f);
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
- A.matrix().set(1, 1, 2.f);
+ A.set_rc(1, 1, 2.f);
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
- A.matrix().set(2, 1, 2.f);
+ A.set_rc(2, 1, 2.f);
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
- A.matrix().set(3, 1, 2.f);
+ A.set_rc(3, 1, 2.f);
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
- A.matrix().set(0, 2, 2.f);
+ A.set_rc(0, 2, 2.f);
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
- A.matrix().set(1, 2, 2.f);
+ A.set_rc(1, 2, 2.f);
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
- A.matrix().set(2, 2, 2.f);
+ A.set_rc(2, 2, 2.f);
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
- A.matrix().set(3, 2, 2.f);
+ A.set_rc(3, 2, 2.f);
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
- A.matrix().set(0, 3, 2.f);
+ A.set_rc(0, 3, 2.f);
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
- A.matrix().set(1, 3, 2.f);
+ A.set_rc(1, 3, 2.f);
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
- A.matrix().set(2, 3, 2.f);
+ A.set_rc(2, 3, 2.f);
EXPECT_FALSE(A.IsIdentity());
A.MakeIdentity();
- A.matrix().set(3, 3, 2.f);
+ A.set_rc(3, 3, 2.f);
EXPECT_FALSE(A.IsIdentity());
}
TEST(XFormTest, verifyIsIdentityOrTranslation) {
- Transform A;
-
- InitializeTestMatrix(&A);
+ Transform A = GetTestMatrix1();
EXPECT_FALSE(A.IsIdentityOrTranslation());
A.MakeIdentity();
@@ -2050,173 +2752,204 @@
// (2, 3) are the translation components, so modifying them should still
// return true.
A.MakeIdentity();
- A.matrix().set(0, 0, 2.f);
+ A.set_rc(0, 0, 2.f);
EXPECT_FALSE(A.IsIdentityOrTranslation());
A.MakeIdentity();
- A.matrix().set(1, 0, 2.f);
+ A.set_rc(1, 0, 2.f);
EXPECT_FALSE(A.IsIdentityOrTranslation());
A.MakeIdentity();
- A.matrix().set(2, 0, 2.f);
+ A.set_rc(2, 0, 2.f);
EXPECT_FALSE(A.IsIdentityOrTranslation());
A.MakeIdentity();
- A.matrix().set(3, 0, 2.f);
+ A.set_rc(3, 0, 2.f);
EXPECT_FALSE(A.IsIdentityOrTranslation());
A.MakeIdentity();
- A.matrix().set(0, 1, 2.f);
+ A.set_rc(0, 1, 2.f);
EXPECT_FALSE(A.IsIdentityOrTranslation());
A.MakeIdentity();
- A.matrix().set(1, 1, 2.f);
+ A.set_rc(1, 1, 2.f);
EXPECT_FALSE(A.IsIdentityOrTranslation());
A.MakeIdentity();
- A.matrix().set(2, 1, 2.f);
+ A.set_rc(2, 1, 2.f);
EXPECT_FALSE(A.IsIdentityOrTranslation());
A.MakeIdentity();
- A.matrix().set(3, 1, 2.f);
+ A.set_rc(3, 1, 2.f);
EXPECT_FALSE(A.IsIdentityOrTranslation());
A.MakeIdentity();
- A.matrix().set(0, 2, 2.f);
+ A.set_rc(0, 2, 2.f);
EXPECT_FALSE(A.IsIdentityOrTranslation());
A.MakeIdentity();
- A.matrix().set(1, 2, 2.f);
+ A.set_rc(1, 2, 2.f);
EXPECT_FALSE(A.IsIdentityOrTranslation());
A.MakeIdentity();
- A.matrix().set(2, 2, 2.f);
+ A.set_rc(2, 2, 2.f);
EXPECT_FALSE(A.IsIdentityOrTranslation());
A.MakeIdentity();
- A.matrix().set(3, 2, 2.f);
+ A.set_rc(3, 2, 2.f);
EXPECT_FALSE(A.IsIdentityOrTranslation());
// Note carefully - expecting true here.
A.MakeIdentity();
- A.matrix().set(0, 3, 2.f);
+ A.set_rc(0, 3, 2.f);
EXPECT_TRUE(A.IsIdentityOrTranslation());
// Note carefully - expecting true here.
A.MakeIdentity();
- A.matrix().set(1, 3, 2.f);
+ A.set_rc(1, 3, 2.f);
EXPECT_TRUE(A.IsIdentityOrTranslation());
// Note carefully - expecting true here.
A.MakeIdentity();
- A.matrix().set(2, 3, 2.f);
+ A.set_rc(2, 3, 2.f);
EXPECT_TRUE(A.IsIdentityOrTranslation());
A.MakeIdentity();
- A.matrix().set(3, 3, 2.f);
+ A.set_rc(3, 3, 2.f);
EXPECT_FALSE(A.IsIdentityOrTranslation());
}
-TEST(XFormTest, verifyIsApproximatelyIdentityOrTranslation) {
- Transform A;
- skia::Matrix44& matrix = A.matrix();
+TEST(XFormTest, ApproximatelyIdentityOrTranslation) {
+ constexpr double kBigError = 1e-4;
+ constexpr double kSmallError = std::numeric_limits<float>::epsilon() / 2.0;
// Exact pure translation.
- A.MakeIdentity();
-
- EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(0));
- EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
- EXPECT_TRUE(A.IsApproximatelyIdentityOrIntegerTranslation(0));
- EXPECT_TRUE(A.IsApproximatelyIdentityOrIntegerTranslation(kApproxZero));
+ Transform a;
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrTranslation(0));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrTranslation(kBigError));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrIntegerTranslation(0));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrIntegerTranslation(kBigError));
// Set translate values to integer values other than 0 or 1.
- matrix.set(0, 3, 3);
- matrix.set(1, 3, 4);
- matrix.set(2, 3, 5);
+ a.set_rc(0, 3, 3);
+ a.set_rc(1, 3, 4);
+ a.set_rc(2, 3, 5);
- EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(0));
- EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
- EXPECT_TRUE(A.IsApproximatelyIdentityOrIntegerTranslation(0));
- EXPECT_TRUE(A.IsApproximatelyIdentityOrIntegerTranslation(kApproxZero));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrTranslation(0));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrTranslation(kBigError));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrIntegerTranslation(0));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrIntegerTranslation(kBigError));
// Set translate values to values other than 0 or 1.
- matrix.set(0, 3, 3.4f);
- matrix.set(1, 3, 4.4f);
- matrix.set(2, 3, 5.6f);
+ a.set_rc(0, 3, 3.4f);
+ a.set_rc(1, 3, 4.4f);
+ a.set_rc(2, 3, 5.6f);
- EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(0));
- EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
- EXPECT_FALSE(A.IsApproximatelyIdentityOrIntegerTranslation(0));
- EXPECT_FALSE(A.IsApproximatelyIdentityOrIntegerTranslation(kApproxZero));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrTranslation(0));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrTranslation(kBigError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrIntegerTranslation(0));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrIntegerTranslation(kBigError));
// Approximately pure translation.
- InitializeApproxIdentityMatrix(&A);
+ a = ApproxIdentityMatrix(kBigError);
- EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
- EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
- EXPECT_FALSE(A.IsApproximatelyIdentityOrIntegerTranslation(0));
- EXPECT_FALSE(A.IsApproximatelyIdentityOrIntegerTranslation(kApproxZero));
+ // All these are false because the perspective error is bigger than the
+ // allowed std::min(float_epsilon, tolerance);
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrTranslation(0));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrTranslation(kBigError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrTranslation(kSmallError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrIntegerTranslation(0));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrTranslation(kBigError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrIntegerTranslation(kSmallError));
- // Some values must be exact.
- matrix.set(3, 0, 0);
- matrix.set(3, 1, 0);
- matrix.set(3, 2, 0);
- matrix.set(3, 3, 1);
+ // Set perspective components to be exact identity.
+ a.set_rc(3, 0, 0);
+ a.set_rc(3, 1, 0);
+ a.set_rc(3, 2, 0);
+ a.set_rc(3, 3, 1);
- EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
- EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
- EXPECT_FALSE(A.IsApproximatelyIdentityOrIntegerTranslation(0));
- EXPECT_TRUE(A.IsApproximatelyIdentityOrIntegerTranslation(kApproxZero));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrTranslation(0));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrTranslation(kBigError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrTranslation(kSmallError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrIntegerTranslation(0));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrIntegerTranslation(kBigError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrIntegerTranslation(kSmallError));
// Set translate values to values other than 0 or 1.
- matrix.set(0, 3, matrix.get(0, 3) + 3);
- matrix.set(1, 3, matrix.get(1, 3) + 4);
- matrix.set(2, 3, matrix.get(2, 3) + 5);
+ // The error is set to kBigError / 2 instead of kBigError because the
+ // arithmetic may make the error bigger.
+ a.set_rc(0, 3, 3.0 + kBigError / 2);
+ a.set_rc(1, 3, 4.0 + kBigError / 2);
+ a.set_rc(2, 3, 5.0 + kBigError / 2);
- EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
- EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
- EXPECT_FALSE(A.IsApproximatelyIdentityOrIntegerTranslation(0));
- EXPECT_TRUE(A.IsApproximatelyIdentityOrIntegerTranslation(kApproxZero));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrTranslation(0));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrTranslation(kBigError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrTranslation(kSmallError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrIntegerTranslation(0));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrIntegerTranslation(kBigError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrIntegerTranslation(kSmallError));
// Set translate values to values other than 0 or 1.
- matrix.set(0, 3, 3.4f);
- matrix.set(1, 3, 4.4f);
- matrix.set(2, 3, 5.6f);
+ a.set_rc(0, 3, 3.4f);
+ a.set_rc(1, 3, 4.4f);
+ a.set_rc(2, 3, 5.6f);
- EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
- EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
- EXPECT_FALSE(A.IsApproximatelyIdentityOrIntegerTranslation(0));
- EXPECT_FALSE(A.IsApproximatelyIdentityOrIntegerTranslation(kApproxZero));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrTranslation(0));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrTranslation(kBigError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrTranslation(kSmallError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrIntegerTranslation(0));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrIntegerTranslation(kBigError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrIntegerTranslation(kSmallError));
- // Not approximately pure translation.
- InitializeApproxIdentityMatrix(&A);
+ // Test with kSmallError in the matrix.
+ a = ApproxIdentityMatrix(kSmallError);
- // Some values must be exact.
- matrix.set(3, 0, 0);
- matrix.set(3, 1, 0);
- matrix.set(3, 2, 0);
- matrix.set(3, 3, 1);
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrTranslation(0));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrTranslation(kBigError));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrTranslation(kSmallError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrIntegerTranslation(0));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrTranslation(kBigError));
+ EXPECT_TRUE(a.IsApproximatelyIdentityOrIntegerTranslation(kSmallError));
// Set some values (not translate values) to values other than 0 or 1.
- matrix.set(0, 1, 3.4f);
- matrix.set(3, 2, 4.4f);
- matrix.set(2, 0, 5.6f);
+ a.set_rc(0, 1, 3.4f);
+ a.set_rc(3, 2, 4.4f);
+ a.set_rc(2, 0, 5.6f);
- EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0));
- EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(kApproxZero));
- EXPECT_FALSE(A.IsApproximatelyIdentityOrIntegerTranslation(0));
- EXPECT_FALSE(A.IsApproximatelyIdentityOrIntegerTranslation(kApproxZero));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrTranslation(0));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrTranslation(kBigError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrTranslation(kSmallError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrIntegerTranslation(0));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrIntegerTranslation(kBigError));
+ EXPECT_FALSE(a.IsApproximatelyIdentityOrIntegerTranslation(kSmallError));
+}
+
+TEST(XFormTest, RoundToIdentityOrIntegerTranslation) {
+ Transform a = ApproxIdentityMatrix(0.1);
+ EXPECT_FALSE(a.IsIdentityOrIntegerTranslation());
+ a.RoundToIdentityOrIntegerTranslation();
+ EXPECT_TRUE(a.IsIdentity());
+ EXPECT_TRUE(a.IsIdentityOrIntegerTranslation());
+
+ a.Translate3d(1.1, 2.2, 3.8);
+ EXPECT_FALSE(a.IsIdentityOrIntegerTranslation());
+ a.RoundToIdentityOrIntegerTranslation();
+ EXPECT_TRUE(a.IsIdentityOrIntegerTranslation());
+ EXPECT_EQ(1.0, a.rc(0, 3));
+ EXPECT_EQ(2.0, a.rc(1, 3));
+ EXPECT_EQ(4.0, a.rc(2, 3));
}
TEST(XFormTest, verifyIsScaleOrTranslation) {
- Transform A;
+ EXPECT_TRUE(Transform().IsScaleOrTranslation());
+ EXPECT_TRUE(Transform::MakeScale(2, 3).IsScaleOrTranslation());
+ EXPECT_TRUE(Transform::MakeTranslation(4, 5).IsScaleOrTranslation());
+ EXPECT_TRUE((Transform::MakeTranslation(4, 5) * Transform::MakeScale(2, 3))
+ .IsScaleOrTranslation());
- InitializeTestMatrix(&A);
+ Transform A = GetTestMatrix1();
EXPECT_FALSE(A.IsScaleOrTranslation());
- A.MakeIdentity();
- EXPECT_TRUE(A.IsScaleOrTranslation());
-
// Modifying any non-scale or non-translation components should cause
// IsScaleOrTranslation() to return false. (0, 0), (1, 1), (2, 2), (0, 3),
// (1, 3), and (2, 3) are the scale and translation components, so
@@ -2224,103 +2957,132 @@
// Note carefully - expecting true here.
A.MakeIdentity();
- A.matrix().set(0, 0, 2.f);
+ EXPECT_TRUE(A.IsScaleOrTranslation());
+ A.set_rc(0, 0, 2.f);
EXPECT_TRUE(A.IsScaleOrTranslation());
A.MakeIdentity();
- A.matrix().set(1, 0, 2.f);
+ A.set_rc(1, 0, 2.f);
EXPECT_FALSE(A.IsScaleOrTranslation());
A.MakeIdentity();
- A.matrix().set(2, 0, 2.f);
+ A.set_rc(2, 0, 2.f);
EXPECT_FALSE(A.IsScaleOrTranslation());
A.MakeIdentity();
- A.matrix().set(3, 0, 2.f);
+ A.set_rc(3, 0, 2.f);
EXPECT_FALSE(A.IsScaleOrTranslation());
A.MakeIdentity();
- A.matrix().set(0, 1, 2.f);
+ A.set_rc(0, 1, 2.f);
EXPECT_FALSE(A.IsScaleOrTranslation());
// Note carefully - expecting true here.
A.MakeIdentity();
- A.matrix().set(1, 1, 2.f);
+ A.set_rc(1, 1, 2.f);
EXPECT_TRUE(A.IsScaleOrTranslation());
A.MakeIdentity();
- A.matrix().set(2, 1, 2.f);
+ A.set_rc(2, 1, 2.f);
EXPECT_FALSE(A.IsScaleOrTranslation());
A.MakeIdentity();
- A.matrix().set(3, 1, 2.f);
+ A.set_rc(3, 1, 2.f);
EXPECT_FALSE(A.IsScaleOrTranslation());
A.MakeIdentity();
- A.matrix().set(0, 2, 2.f);
+ A.set_rc(0, 2, 2.f);
EXPECT_FALSE(A.IsScaleOrTranslation());
A.MakeIdentity();
- A.matrix().set(1, 2, 2.f);
+ A.set_rc(1, 2, 2.f);
EXPECT_FALSE(A.IsScaleOrTranslation());
// Note carefully - expecting true here.
A.MakeIdentity();
- A.matrix().set(2, 2, 2.f);
+ A.set_rc(2, 2, 2.f);
EXPECT_TRUE(A.IsScaleOrTranslation());
A.MakeIdentity();
- A.matrix().set(3, 2, 2.f);
+ A.set_rc(3, 2, 2.f);
EXPECT_FALSE(A.IsScaleOrTranslation());
// Note carefully - expecting true here.
A.MakeIdentity();
- A.matrix().set(0, 3, 2.f);
+ A.set_rc(0, 3, 2.f);
EXPECT_TRUE(A.IsScaleOrTranslation());
// Note carefully - expecting true here.
A.MakeIdentity();
- A.matrix().set(1, 3, 2.f);
+ A.set_rc(1, 3, 2.f);
EXPECT_TRUE(A.IsScaleOrTranslation());
// Note carefully - expecting true here.
A.MakeIdentity();
- A.matrix().set(2, 3, 2.f);
+ A.set_rc(2, 3, 2.f);
EXPECT_TRUE(A.IsScaleOrTranslation());
A.MakeIdentity();
- A.matrix().set(3, 3, 2.f);
+ A.set_rc(3, 3, 2.f);
EXPECT_FALSE(A.IsScaleOrTranslation());
}
-TEST(XFormTest, verifyFlattenTo2d) {
- Transform A;
- InitializeTestMatrix(&A);
+TEST(XFormTest, To2dScale) {
+ Transform t;
+ EXPECT_TRUE(t.IsScale2d());
+ EXPECT_EQ(Vector2dF(1, 1), t.To2dScale());
- A.FlattenTo2d();
- EXPECT_ROW1_EQ(10.0f, 14.0f, 0.0f, 22.0f, A);
- EXPECT_ROW2_EQ(11.0f, 15.0f, 0.0f, 23.0f, A);
- EXPECT_ROW3_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
- EXPECT_ROW4_EQ(13.0f, 17.0f, 0.0f, 25.0f, A);
+ t.Scale(2.5f, 3.75f);
+ EXPECT_TRUE(t.IsScale2d());
+ EXPECT_EQ(Vector2dF(2.5f, 3.75f), t.To2dScale());
+
+ t.EnsureFullMatrixForTesting();
+ EXPECT_TRUE(t.IsScale2d());
+ EXPECT_EQ(Vector2dF(2.5f, 3.75f), t.To2dScale());
+
+ t.Scale3d(3, 4, 5);
+ EXPECT_FALSE(t.IsScale2d());
+ EXPECT_EQ(Vector2dF(7.5f, 15.f), t.To2dScale());
+
+ for (int row = 0; row < 4; row++) {
+ for (int col = 0; col < 4; col++) {
+ t.MakeIdentity();
+ t.set_rc(row, col, 100);
+ bool is_scale_2d = row == col && (row == 0 || row == 1);
+ EXPECT_EQ(is_scale_2d, t.IsScale2d()) << " row=" << row << " col=" << col;
+ }
+ }
+}
+
+TEST(XFormTest, Flatten) {
+ Transform A = GetTestMatrix1();
+ EXPECT_FALSE(A.IsFlat());
+
+ A.Flatten();
+ EXPECT_ROW0_EQ(10.0f, 14.0f, 0.0f, 22.0f, A);
+ EXPECT_ROW1_EQ(11.0f, 15.0f, 0.0f, 23.0f, A);
+ EXPECT_ROW2_EQ(0.0f, 0.0f, 1.0f, 0.0f, A);
+ EXPECT_ROW3_EQ(13.0f, 17.0f, 0.0f, 25.0f, A);
+
+ EXPECT_TRUE(A.IsFlat());
}
TEST(XFormTest, IsFlat) {
- Transform transform;
- InitializeTestMatrix(&transform);
+ Transform transform = GetTestMatrix1();
// A transform with all entries non-zero isn't flat.
EXPECT_FALSE(transform.IsFlat());
- transform.matrix().set(0, 2, 0.f);
- transform.matrix().set(1, 2, 0.f);
- transform.matrix().set(2, 2, 1.f);
- transform.matrix().set(3, 2, 0.f);
+ transform.set_rc(0, 2, 0.f);
+ transform.set_rc(1, 2, 0.f);
+ transform.set_rc(2, 2, 1.f);
+ transform.set_rc(3, 2, 0.f);
EXPECT_FALSE(transform.IsFlat());
- transform.matrix().set(2, 0, 0.f);
- transform.matrix().set(2, 1, 0.f);
- transform.matrix().set(2, 3, 0.f);
+ transform.set_rc(2, 0, 0.f);
+ transform.set_rc(2, 1, 0.f);
+ transform.set_rc(2, 3, 0.f);
// Since the third column and row are both (0, 0, 1, 0), the transform is
// flat.
@@ -2339,10 +3101,10 @@
PointF(p3.x(), p3.y()), PointF(p4.x(), p4.y()));
EXPECT_TRUE(test_quad.IsRectilinear());
- transform.TransformPoint(&p1);
- transform.TransformPoint(&p2);
- transform.TransformPoint(&p3);
- transform.TransformPoint(&p4);
+ p1 = transform.MapPoint(p1);
+ p2 = transform.MapPoint(p2);
+ p3 = transform.MapPoint(p3);
+ p4 = transform.MapPoint(p4);
QuadF transformedQuad(PointF(p1.x(), p1.y()), PointF(p2.x(), p2.y()),
PointF(p3.x(), p3.y()), PointF(p4.x(), p4.y()));
@@ -2351,54 +3113,54 @@
TEST(XFormTest, Preserves2dAxisAlignment) {
static const struct TestCase {
- SkScalar a; // row 1, column 1
- SkScalar b; // row 1, column 2
- SkScalar c; // row 2, column 1
- SkScalar d; // row 2, column 2
+ double a; // row 1, column 1
+ double b; // row 1, column 2
+ double c; // row 2, column 1
+ double d; // row 2, column 2
bool expected;
bool degenerate;
} test_cases[] = {
// clang-format off
- { 3.f, 0.f,
- 0.f, 4.f, true, false }, // basic case
- { 0.f, 4.f,
- 3.f, 0.f, true, false }, // rotate by 90
- { 0.f, 0.f,
- 0.f, 4.f, true, true }, // degenerate x
- { 3.f, 0.f,
- 0.f, 0.f, true, true }, // degenerate y
- { 0.f, 0.f,
- 3.f, 0.f, true, true }, // degenerate x + rotate by 90
- { 0.f, 4.f,
- 0.f, 0.f, true, true }, // degenerate y + rotate by 90
- { 3.f, 4.f,
- 0.f, 0.f, false, true },
- { 0.f, 0.f,
- 3.f, 4.f, false, true },
- { 0.f, 3.f,
- 0.f, 4.f, false, true },
- { 3.f, 0.f,
- 4.f, 0.f, false, true },
- { 3.f, 4.f,
- 5.f, 0.f, false, false },
- { 3.f, 4.f,
- 0.f, 5.f, false, false },
- { 3.f, 0.f,
- 4.f, 5.f, false, false },
- { 0.f, 3.f,
- 4.f, 5.f, false, false },
- { 2.f, 3.f,
- 4.f, 5.f, false, false },
+ { 3.0, 0.0,
+ 0.0, 4.0, true, false }, // basic case
+ { 0.0, 4.0,
+ 3.0, 0.0, true, false }, // rotate by 90
+ { 0.0, 0.0,
+ 0.0, 4.0, true, true }, // degenerate x
+ { 3.0, 0.0,
+ 0.0, 0.0, true, true }, // degenerate y
+ { 0.0, 0.0,
+ 3.0, 0.0, true, true }, // degenerate x + rotate by 90
+ { 0.0, 4.0,
+ 0.0, 0.0, true, true }, // degenerate y + rotate by 90
+ { 3.0, 4.0,
+ 0.0, 0.0, false, true },
+ { 0.0, 0.0,
+ 3.0, 4.0, false, true },
+ { 0.0, 3.0,
+ 0.0, 4.0, false, true },
+ { 3.0, 0.0,
+ 4.0, 0.0, false, true },
+ { 3.0, 4.0,
+ 5.0, 0.0, false, false },
+ { 3.0, 4.0,
+ 0.0, 5.0, false, false },
+ { 3.0, 0.0,
+ 4.0, 5.0, false, false },
+ { 0.0, 3.0,
+ 4.0, 5.0, false, false },
+ { 2.0, 3.0,
+ 4.0, 5.0, false, false },
// clang-format on
};
Transform transform;
for (const auto& value : test_cases) {
transform.MakeIdentity();
- transform.matrix().set(0, 0, value.a);
- transform.matrix().set(0, 1, value.b);
- transform.matrix().set(1, 0, value.c);
- transform.matrix().set(1, 1, value.d);
+ transform.set_rc(0, 0, value.a);
+ transform.set_rc(0, 1, value.b);
+ transform.set_rc(1, 0, value.c);
+ transform.set_rc(1, 1, value.d);
if (value.expected) {
EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
@@ -2419,19 +3181,19 @@
// elements (except perspective) have entries, to test that they are ignored.
for (const auto& value : test_cases) {
transform.MakeIdentity();
- transform.matrix().set(0, 0, value.a);
- transform.matrix().set(0, 1, value.b);
- transform.matrix().set(1, 0, value.c);
- transform.matrix().set(1, 1, value.d);
+ transform.set_rc(0, 0, value.a);
+ transform.set_rc(0, 1, value.b);
+ transform.set_rc(1, 0, value.c);
+ transform.set_rc(1, 1, value.d);
- transform.matrix().set(0, 2, 1.f);
- transform.matrix().set(0, 3, 2.f);
- transform.matrix().set(1, 2, 3.f);
- transform.matrix().set(1, 3, 4.f);
- transform.matrix().set(2, 0, 5.f);
- transform.matrix().set(2, 1, 6.f);
- transform.matrix().set(2, 2, 7.f);
- transform.matrix().set(2, 3, 8.f);
+ transform.set_rc(0, 2, 1.f);
+ transform.set_rc(0, 3, 2.f);
+ transform.set_rc(1, 2, 3.f);
+ transform.set_rc(1, 3, 4.f);
+ transform.set_rc(2, 0, 5.f);
+ transform.set_rc(2, 1, 6.f);
+ transform.set_rc(2, 2, 7.f);
+ transform.set_rc(2, 3, 8.f);
if (value.expected) {
EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
@@ -2452,23 +3214,23 @@
// always assumed to not-preserve axis alignment.
for (const auto& value : test_cases) {
transform.MakeIdentity();
- transform.matrix().set(0, 0, value.a);
- transform.matrix().set(0, 1, value.b);
- transform.matrix().set(1, 0, value.c);
- transform.matrix().set(1, 1, value.d);
+ transform.set_rc(0, 0, value.a);
+ transform.set_rc(0, 1, value.b);
+ transform.set_rc(1, 0, value.c);
+ transform.set_rc(1, 1, value.d);
- transform.matrix().set(0, 2, 1.f);
- transform.matrix().set(0, 3, 2.f);
- transform.matrix().set(1, 2, 3.f);
- transform.matrix().set(1, 3, 4.f);
- transform.matrix().set(2, 0, 5.f);
- transform.matrix().set(2, 1, 6.f);
- transform.matrix().set(2, 2, 7.f);
- transform.matrix().set(2, 3, 8.f);
- transform.matrix().set(3, 0, 9.f);
- transform.matrix().set(3, 1, 10.f);
- transform.matrix().set(3, 2, 11.f);
- transform.matrix().set(3, 3, 12.f);
+ transform.set_rc(0, 2, 1.f);
+ transform.set_rc(0, 3, 2.f);
+ transform.set_rc(1, 2, 3.f);
+ transform.set_rc(1, 3, 4.f);
+ transform.set_rc(2, 0, 5.f);
+ transform.set_rc(2, 1, 6.f);
+ transform.set_rc(2, 2, 7.f);
+ transform.set_rc(2, 3, 8.f);
+ transform.set_rc(3, 0, 9.f);
+ transform.set_rc(3, 1, 10.f);
+ transform.set_rc(3, 2, 11.f);
+ transform.set_rc(3, 3, 12.f);
EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform));
EXPECT_FALSE(transform.Preserves2dAxisAlignment());
@@ -2477,52 +3239,53 @@
// Try a few more practical situations to check precision
transform.MakeIdentity();
- transform.RotateAboutZAxis(90.0);
+ constexpr double kNear90Degrees = 90.0 + kErrorThreshold / 2;
+ transform.RotateAboutZAxis(kNear90Degrees);
EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
EXPECT_TRUE(transform.Preserves2dAxisAlignment());
EXPECT_TRUE(transform.NonDegeneratePreserves2dAxisAlignment());
transform.MakeIdentity();
- transform.RotateAboutZAxis(180.0);
+ transform.RotateAboutZAxis(kNear90Degrees * 2);
EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
EXPECT_TRUE(transform.Preserves2dAxisAlignment());
EXPECT_TRUE(transform.NonDegeneratePreserves2dAxisAlignment());
transform.MakeIdentity();
- transform.RotateAboutZAxis(270.0);
+ transform.RotateAboutZAxis(kNear90Degrees * 3);
EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
EXPECT_TRUE(transform.Preserves2dAxisAlignment());
EXPECT_TRUE(transform.NonDegeneratePreserves2dAxisAlignment());
transform.MakeIdentity();
- transform.RotateAboutYAxis(90.0);
+ transform.RotateAboutYAxis(kNear90Degrees);
EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
EXPECT_TRUE(transform.Preserves2dAxisAlignment());
EXPECT_FALSE(transform.NonDegeneratePreserves2dAxisAlignment());
transform.MakeIdentity();
- transform.RotateAboutXAxis(90.0);
+ transform.RotateAboutXAxis(kNear90Degrees);
EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
EXPECT_TRUE(transform.Preserves2dAxisAlignment());
EXPECT_FALSE(transform.NonDegeneratePreserves2dAxisAlignment());
transform.MakeIdentity();
- transform.RotateAboutZAxis(90.0);
- transform.RotateAboutYAxis(90.0);
+ transform.RotateAboutZAxis(kNear90Degrees);
+ transform.RotateAboutYAxis(kNear90Degrees);
EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
EXPECT_TRUE(transform.Preserves2dAxisAlignment());
EXPECT_FALSE(transform.NonDegeneratePreserves2dAxisAlignment());
transform.MakeIdentity();
- transform.RotateAboutZAxis(90.0);
- transform.RotateAboutXAxis(90.0);
+ transform.RotateAboutZAxis(kNear90Degrees);
+ transform.RotateAboutXAxis(kNear90Degrees);
EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
EXPECT_TRUE(transform.Preserves2dAxisAlignment());
EXPECT_FALSE(transform.NonDegeneratePreserves2dAxisAlignment());
transform.MakeIdentity();
- transform.RotateAboutYAxis(90.0);
- transform.RotateAboutZAxis(90.0);
+ transform.RotateAboutYAxis(kNear90Degrees);
+ transform.RotateAboutZAxis(kNear90Degrees);
EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
EXPECT_TRUE(transform.Preserves2dAxisAlignment());
EXPECT_FALSE(transform.NonDegeneratePreserves2dAxisAlignment());
@@ -2574,20 +3337,20 @@
// be positive.
// clang-format off
- transform = Transform(1.0, 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, -1.0);
+ transform = Transform::RowMajor(1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, -1.0);
// clang-format on
EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
EXPECT_TRUE(transform.Preserves2dAxisAlignment());
EXPECT_FALSE(transform.NonDegeneratePreserves2dAxisAlignment());
// clang-format off
- transform = Transform(2.0, 0.0, 0.0, 0.0,
- 0.0, 5.0, 0.0, 0.0,
- 0.0, 0.0, 1.0, 0.0,
- 0.0, 0.0, 0.0, 0.0);
+ transform = Transform::RowMajor(2.0, 0.0, 0.0, 0.0,
+ 0.0, 5.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 0.0);
// clang-format on
EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform));
EXPECT_TRUE(transform.Preserves2dAxisAlignment());
@@ -2598,132 +3361,740 @@
Vector2dF translation(3.f, 7.f);
Transform transform;
transform.Translate(translation.x(), translation.y() + 1);
- EXPECT_NE(translation.ToString(), transform.To2dTranslation().ToString());
+ EXPECT_NE(translation, transform.To2dTranslation());
transform.MakeIdentity();
transform.Translate(translation.x(), translation.y());
- EXPECT_EQ(translation.ToString(), transform.To2dTranslation().ToString());
+ transform.set_rc(1, 1, 100);
+ EXPECT_EQ(translation, transform.To2dTranslation());
}
-TEST(XFormTest, TransformRect) {
- Transform translation;
- translation.Translate(3.f, 7.f);
- RectF rect(1.f, 2.f, 3.f, 4.f);
- RectF expected(4.f, 9.f, 3.f, 4.f);
- translation.TransformRect(&rect);
- EXPECT_EQ(expected.ToString(), rect.ToString());
+TEST(XFormTest, To3dTranslation) {
+ Transform transform;
+ EXPECT_EQ(gfx::Vector3dF(), transform.To3dTranslation());
+ transform.Translate(10, 20);
+ EXPECT_EQ(gfx::Vector3dF(10, 20, 0), transform.To3dTranslation());
+ transform.Translate3d(20, -60, -10);
+ EXPECT_EQ(gfx::Vector3dF(30, -40, -10), transform.To3dTranslation());
+ transform.set_rc(1, 1, 100);
+ EXPECT_EQ(gfx::Vector3dF(30, -40, -10), transform.To3dTranslation());
+}
+
+TEST(XFormTest, MapRect) {
+ Transform translation = Transform::MakeTranslation(3.25f, 7.75f);
+ RectF rect(1.25f, 2.5f, 3.75f, 4.f);
+ RectF expected(4.5f, 10.25f, 3.75f, 4.f);
+ EXPECT_EQ(expected, translation.MapRect(rect));
+
+ EXPECT_EQ(rect, Transform().MapRect(rect));
+
+ auto singular = Transform::MakeScale(0.f);
+ EXPECT_EQ(RectF(0, 0, 0, 0), singular.MapRect(rect));
+
+ auto negative_scale = Transform::MakeScale(-1, -2);
+ EXPECT_EQ(RectF(-5.f, -13.f, 3.75f, 8.f), negative_scale.MapRect(rect));
+
+ auto rotate = Transform::Make90degRotation();
+ EXPECT_EQ(RectF(-6.5f, 1.25f, 4.f, 3.75f), rotate.MapRect(rect));
+}
+
+TEST(XFormTest, MapIntRect) {
+ auto translation = Transform::MakeTranslation(3.25f, 7.75f);
+ EXPECT_EQ(Rect(4, 9, 4, 5), translation.MapRect(Rect(1, 2, 3, 4)));
+
+ EXPECT_EQ(Rect(1, 2, 3, 4), Transform().MapRect(Rect(1, 2, 3, 4)));
+
+ auto singular = Transform::MakeScale(0.f);
+ EXPECT_EQ(Rect(0, 0, 0, 0), singular.MapRect(Rect(1, 2, 3, 4)));
}
TEST(XFormTest, TransformRectReverse) {
- Transform translation;
- translation.Translate(3.f, 7.f);
- RectF rect(1.f, 2.f, 3.f, 4.f);
- RectF expected(-2.f, -5.f, 3.f, 4.f);
- EXPECT_TRUE(translation.TransformRectReverse(&rect));
- EXPECT_EQ(expected.ToString(), rect.ToString());
+ auto translation = Transform::MakeTranslation(3.25f, 7.75f);
+ RectF rect(1.25f, 2.5f, 3.75f, 4.f);
+ RectF expected(-2.f, -5.25f, 3.75f, 4.f);
+ EXPECT_EQ(expected, translation.InverseMapRect(rect));
- Transform singular;
- singular.Scale3d(0.f, 0.f, 0.f);
- EXPECT_FALSE(singular.TransformRectReverse(&rect));
+ EXPECT_EQ(rect, Transform().InverseMapRect(rect));
+
+ auto singular = Transform::MakeScale(0.f);
+ EXPECT_FALSE(singular.InverseMapRect(rect));
+
+ auto negative_scale = Transform::MakeScale(-1, -2);
+ EXPECT_EQ(RectF(-5.f, -3.25f, 3.75f, 2.f),
+ negative_scale.InverseMapRect(rect));
+
+ auto rotate = Transform::Make90degRotation();
+ EXPECT_EQ(RectF(2.5f, -5.f, 4.f, 3.75f), rotate.InverseMapRect(rect));
}
-TEST(XFormTest, TransformRRectF) {
- Transform translation;
- translation.Translate(-3.f, -7.f);
- RRectF rrect(1.f, 2.f, 20.f, 25.f, 5.f);
- RRectF expected(-2.f, -5.f, 20.f, 25.f, 5.f);
- EXPECT_TRUE(translation.TransformRRectF(&rrect));
- EXPECT_EQ(expected.ToString(), rrect.ToString());
+TEST(XFormTest, InverseMapIntRect) {
+ auto translation = Transform::MakeTranslation(3.25f, 7.75f);
+ EXPECT_EQ(Rect(-3, -6, 4, 5), translation.InverseMapRect(Rect(1, 2, 3, 4)));
- skia::Matrix44 rot(skia::Matrix44::kUninitialized_Constructor);
- rot.set3x3(0, 1, 0, -1, 0, 0, 0, 0, 1);
- Transform rotation_90_Clock(rot);
+ EXPECT_EQ(Rect(1, 2, 3, 4), Transform().InverseMapRect(Rect(1, 2, 3, 4)));
- rrect = RRectF(gfx::RectF(0, 0, 20.f, 25.f),
- gfx::RoundedCornersF(1.f, 2.f, 3.f, 4.f));
- expected = RRectF(gfx::RectF(-25.f, 0, 25.f, 20.f),
- gfx::RoundedCornersF(4.f, 1.f, 2.f, 3.f));
- EXPECT_TRUE(rotation_90_Clock.TransformRRectF(&rrect));
- EXPECT_EQ(expected.ToString(), rrect.ToString());
-
- Transform scale;
- scale.Scale(2.f, 2.f);
- rrect = RRectF(gfx::RectF(0, 0, 20.f, 25.f),
- gfx::RoundedCornersF(1.f, 2.f, 3.f, 4.f));
- expected = RRectF(gfx::RectF(0, 0, 40.f, 50.f),
- gfx::RoundedCornersF(2.f, 4.f, 6.f, 8.f));
- EXPECT_TRUE(scale.TransformRRectF(&rrect));
- EXPECT_EQ(expected.ToString(), rrect.ToString());
+ auto singular = Transform::MakeScale(0.f);
+ EXPECT_FALSE(singular.InverseMapRect(Rect(1, 2, 3, 4)));
}
-TEST(XFormTest, TransformBox) {
+TEST(XFormTest, MapQuad) {
+ auto translation = Transform::MakeTranslation(3.25f, 7.75f);
+ QuadF q(PointF(1.25f, 2.5f), PointF(3.75f, 4.f), PointF(23.f, 45.f),
+ PointF(12.f, 67.f));
+ EXPECT_EQ(QuadF(PointF(4.5f, 10.25f), PointF(7.f, 11.75f),
+ PointF(26.25f, 52.75f), PointF(15.25f, 74.75f)),
+ translation.MapQuad(q));
+
+ EXPECT_EQ(q, Transform().MapQuad(q));
+
+ auto singular = Transform::MakeScale(0.f);
+ EXPECT_EQ(QuadF(), singular.MapQuad(q));
+
+ auto negative_scale = Transform::MakeScale(-1, -2);
+ EXPECT_EQ(QuadF(PointF(-1.25f, -5.f), PointF(-3.75f, -8.f),
+ PointF(-23.f, -90.f), PointF(-12.f, -134.f)),
+ negative_scale.MapQuad(q));
+
+ auto rotate = Transform::Make90degRotation();
+ EXPECT_EQ(QuadF(PointF(-2.5f, 1.25f), PointF(-4.f, 3.75f),
+ PointF(-45.f, 23.f), PointF(-67.f, 12.f)),
+ rotate.MapQuad(q));
+}
+
+TEST(XFormTest, MapBox) {
Transform translation;
translation.Translate3d(3.f, 7.f, 6.f);
BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
BoxF expected(4.f, 9.f, 9.f, 4.f, 5.f, 6.f);
- translation.TransformBox(&box);
- EXPECT_EQ(expected.ToString(), box.ToString());
+ BoxF transformed = translation.MapBox(box);
+ EXPECT_EQ(expected, transformed);
}
-TEST(XFormTest, TransformBoxReverse) {
- Transform translation;
- translation.Translate3d(3.f, 7.f, 6.f);
- BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f);
- BoxF expected(-2.f, -5.f, -3.f, 4.f, 5.f, 6.f);
- EXPECT_TRUE(translation.TransformBoxReverse(&box));
- EXPECT_EQ(expected.ToString(), box.ToString());
-
- Transform singular;
- singular.Scale3d(0.f, 0.f, 0.f);
- EXPECT_FALSE(singular.TransformBoxReverse(&box));
-}
-
-TEST(XFormTest, RoundTranslationComponents) {
+TEST(XFormTest, Round2dTranslationComponents) {
Transform translation;
Transform expected;
- translation.RoundTranslationComponents();
+ translation.Round2dTranslationComponents();
EXPECT_EQ(expected.ToString(), translation.ToString());
translation.Translate(1.0f, 1.0f);
expected.Translate(1.0f, 1.0f);
- translation.RoundTranslationComponents();
+ translation.Round2dTranslationComponents();
EXPECT_EQ(expected.ToString(), translation.ToString());
translation.Translate(0.5f, 0.4f);
expected.Translate(1.0f, 0.0f);
- translation.RoundTranslationComponents();
+ translation.Round2dTranslationComponents();
EXPECT_EQ(expected.ToString(), translation.ToString());
// Rounding should only affect 2d translation components.
translation.Translate3d(0.f, 0.f, 0.5f);
expected.Translate3d(0.f, 0.f, 0.5f);
- translation.RoundTranslationComponents();
+ translation.Round2dTranslationComponents();
EXPECT_EQ(expected.ToString(), translation.ToString());
}
TEST(XFormTest, BackFaceVisiblilityTolerance) {
Transform backface_invisible;
- backface_invisible.matrix().set(0, 3, 1.f);
- backface_invisible.matrix().set(3, 0, 1.f);
- backface_invisible.matrix().set(2, 0, 1.f);
- backface_invisible.matrix().set(3, 2, 1.f);
+ backface_invisible.set_rc(0, 3, 1.f);
+ backface_invisible.set_rc(3, 0, 1.f);
+ backface_invisible.set_rc(2, 0, 1.f);
+ backface_invisible.set_rc(3, 2, 1.f);
// The transformation matrix has a determinant = 1 and cofactor33 = 0. So,
// IsBackFaceVisible should return false.
- EXPECT_EQ(backface_invisible.matrix().determinant(), 1.f);
+ EXPECT_EQ(backface_invisible.Determinant(), 1.f);
EXPECT_FALSE(backface_invisible.IsBackFaceVisible());
// Adding a noise to the transformsation matrix that is within the tolerance
// (machine epsilon) should not change the result.
float noise = std::numeric_limits<float>::epsilon();
- backface_invisible.matrix().set(0, 3, 1.f + noise);
+ backface_invisible.set_rc(0, 3, 1.f + noise);
EXPECT_FALSE(backface_invisible.IsBackFaceVisible());
// A noise that is more than the tolerance should change the result.
- backface_invisible.matrix().set(0, 3, 1.f + (2 * noise));
+ backface_invisible.set_rc(0, 3, 1.f + (2 * noise));
EXPECT_TRUE(backface_invisible.IsBackFaceVisible());
}
+TEST(XFormTest, TransformVector4) {
+ Transform transform;
+ transform.set_rc(0, 0, 2.5f);
+ transform.set_rc(1, 1, 3.5f);
+ transform.set_rc(2, 2, 4.5f);
+ transform.set_rc(3, 3, 5.5f);
+ std::array<float, 4> input = {11.5f, 22.5f, 33.5f, 44.5f};
+ auto vector = input;
+ std::array<float, 4> expected = {28.75f, 78.75f, 150.75f, 244.75f};
+ transform.TransformVector4(vector.data());
+ EXPECT_EQ(expected, vector);
+
+ // With translations and perspectives.
+ transform.set_rc(0, 3, 10);
+ transform.set_rc(1, 3, 20);
+ transform.set_rc(2, 3, 30);
+ transform.set_rc(3, 0, 40);
+ transform.set_rc(3, 1, 50);
+ transform.set_rc(3, 2, 60);
+ vector = input;
+ expected = {473.75f, 968.75f, 1485.75f, 3839.75f};
+ transform.TransformVector4(vector.data());
+ EXPECT_EQ(expected, vector);
+
+ // TransformVector4 with simple 2d transform.
+ transform =
+ Transform::MakeTranslation(10, 20) * Transform::MakeScale(2.5f, 3.5f);
+ vector = input;
+ expected = {473.75f, 968.75f, 33.5f, 44.5f};
+ transform.TransformVector4(vector.data());
+ EXPECT_EQ(expected, vector);
+
+ vector = input;
+ transform.EnsureFullMatrixForTesting();
+ transform.TransformVector4(vector.data());
+ EXPECT_EQ(expected, vector);
+}
+
+TEST(XFormTest, Make90NRotation) {
+ auto t1 = Transform::Make90degRotation();
+ EXPECT_EQ(gfx::PointF(-50, 100), t1.MapPoint(gfx::PointF(100, 50)));
+
+ auto t2 = Transform::Make180degRotation();
+ EXPECT_EQ(Transform::MakeScale(-1), t2);
+ EXPECT_EQ(gfx::PointF(-100, -50), t2.MapPoint(gfx::PointF(100, 50)));
+
+ auto t3 = Transform::Make270degRotation();
+ EXPECT_EQ(gfx::PointF(50, -100), t3.MapPoint(gfx::PointF(100, 50)));
+
+ auto t4 = t1 * t1;
+ EXPECT_EQ(t2, t4);
+ t4.PreConcat(t1);
+ EXPECT_EQ(t3, t4);
+ t4.PreConcat(t1);
+ EXPECT_TRUE(t4.IsIdentity());
+ t2.PreConcat(t2);
+ EXPECT_TRUE(t2.IsIdentity());
+}
+
+TEST(XFormTest, Rotate90NDegrees) {
+ Transform t1;
+ t1.Rotate(90);
+ EXPECT_EQ(Transform::Make90degRotation(), t1);
+
+ Transform t2;
+ t2.Rotate(180);
+ EXPECT_EQ(Transform::Make180degRotation(), t2);
+
+ Transform t3;
+ t3.Rotate(270);
+ EXPECT_EQ(Transform::Make270degRotation(), t3);
+
+ Transform t4;
+ t4.Rotate(360);
+ EXPECT_EQ(Transform(), t4);
+ t4.Rotate(-270);
+ EXPECT_EQ(t1, t4);
+ t4.Rotate(-180);
+ EXPECT_EQ(t3, t4);
+ t4.Rotate(270);
+ EXPECT_EQ(t2, t4);
+
+ t1.Rotate(-90);
+ t2.Rotate(180);
+ t3.Rotate(-270);
+ t4.Rotate(-180);
+ EXPECT_TRUE(t1.IsIdentity());
+ EXPECT_TRUE(t2.IsIdentity());
+ EXPECT_TRUE(t3.IsIdentity());
+ EXPECT_TRUE(t4.IsIdentity());
+
+ // This should not crash. https://crbug.com/1378323.
+ Transform t;
+ t.Rotate(-1e-30);
+}
+
+TEST(XFormTest, MapPoint) {
+ Transform transform;
+ transform.Translate3d(1.25f, 2.75f, 3.875f);
+ transform.Scale3d(3, 4, 5);
+ EXPECT_EQ(PointF(38.75f, 140.75f), transform.MapPoint(PointF(12.5f, 34.5f)));
+ EXPECT_EQ(Point3F(38.75f, 140.75f, 286.375f),
+ transform.MapPoint(Point3F(12.5f, 34.5f, 56.5f)));
+
+ transform.MakeIdentity();
+ transform.set_rc(3, 0, 0.5);
+ transform.set_rc(3, 1, 2);
+ transform.set_rc(3, 2, 0.75);
+ EXPECT_POINTF_EQ(PointF(0.2, 0.4), transform.MapPoint(PointF(2, 4)));
+ EXPECT_POINT3F_EQ(Point3F(0.18181818f, 0.27272727f, 0.36363636f),
+ transform.MapPoint(Point3F(2, 3, 4)));
+
+ // 0 in all perspectives should be ignored.
+ transform.MakeIdentity();
+ transform.Translate3d(10, 20, 30);
+ transform.set_rc(3, 3, 0);
+ EXPECT_EQ(PointF(12, 24), transform.MapPoint(PointF(2, 4)));
+ EXPECT_EQ(Point3F(12, 23, 34), transform.MapPoint(Point3F(2, 3, 4)));
+
+ // NaN in perspective should be ignored.
+ transform.set_rc(3, 3, std::numeric_limits<float>::quiet_NaN());
+ EXPECT_EQ(PointF(12, 24), transform.MapPoint(PointF(2, 4)));
+ EXPECT_EQ(Point3F(12, 23, 34), transform.MapPoint(Point3F(2, 3, 4)));
+
+ // MapPoint with simple 2d transform.
+ transform = Transform::MakeTranslation(10, 20) * Transform::MakeScale(3, 4);
+ EXPECT_EQ(PointF(47.5f, 158.0f), transform.MapPoint(PointF(12.5f, 34.5f)));
+ EXPECT_EQ(Point3F(47.5f, 158.0f, 56.5f),
+ transform.MapPoint(Point3F(12.5f, 34.5f, 56.5f)));
+
+ transform.EnsureFullMatrixForTesting();
+ EXPECT_EQ(PointF(47.5f, 158.0f), transform.MapPoint(PointF(12.5f, 34.5f)));
+ EXPECT_EQ(Point3F(47.5f, 158.0f, 56.5f),
+ transform.MapPoint(Point3F(12.5f, 34.5f, 56.5f)));
+}
+
+TEST(XFormTest, InverseMapPoint) {
+ Transform transform;
+ transform.Translate(1, 2);
+ transform.Rotate(70);
+ transform.Scale(3, 4);
+ transform.Skew(30, 70);
+
+ const PointF point_f(12.34f, 56.78f);
+ PointF transformed_point_f = transform.MapPoint(point_f);
+ const absl::optional<PointF> reverted_point_f =
+ transform.InverseMapPoint(transformed_point_f);
+ ASSERT_TRUE(reverted_point_f.has_value());
+ EXPECT_TRUE(PointsAreNearlyEqual(reverted_point_f.value(), point_f));
+
+ const Point point(12, 13);
+ Point transformed_point = transform.MapPoint(point);
+ EXPECT_EQ(point, transform.InverseMapPoint(transformed_point));
+
+ Transform transform3d;
+ transform3d.Translate3d(1, 2, 3);
+ transform3d.RotateAbout(Vector3dF(4, 5, 6), 70);
+ transform3d.Scale3d(7, 8, 9);
+ transform3d.Skew(30, 70);
+
+ const Point3F point_3f(14, 15, 16);
+ Point3F transformed_point_3f = transform3d.MapPoint(point_3f);
+ const absl::optional<Point3F> reverted_point_3f =
+ transform3d.InverseMapPoint(transformed_point_3f);
+ ASSERT_TRUE(reverted_point_3f.has_value());
+ EXPECT_TRUE(PointsAreNearlyEqual(reverted_point_3f.value(), point_3f));
+
+ // MapPoint with simple 2d transform.
+ transform = Transform::MakeTranslation(10, 20) * Transform::MakeScale(3, 4);
+ EXPECT_EQ(PointF(47.5f, 158.0f), transform.MapPoint(PointF(12.5f, 34.5f)));
+ EXPECT_EQ(Point3F(47.5f, 158.0f, 56.5f),
+ transform.MapPoint(Point3F(12.5f, 34.5f, 56.5f)));
+
+ transform.EnsureFullMatrixForTesting();
+ EXPECT_EQ(PointF(47.5f, 158.0f), transform.MapPoint(PointF(12.5f, 34.5f)));
+ EXPECT_EQ(Point3F(47.5f, 158.0f, 56.5f),
+ transform.MapPoint(Point3F(12.5f, 34.5f, 56.5f)));
+}
+
+TEST(XFormTest, MapVector) {
+ Transform transform;
+ transform.Scale3d(3, 4, 5);
+ Vector3dF vector(12.5f, 34.5f, 56.5f);
+ Vector3dF expected(37.5f, 138.0f, 282.5f);
+ EXPECT_EQ(expected, transform.MapVector(vector));
+
+ // The translation components should be ignored.
+ transform.Translate3d(1.25f, 2.75f, 3.875f);
+ EXPECT_EQ(expected, transform.MapVector(vector));
+
+ // The perspective components should be ignored.
+ transform.set_rc(3, 0, 0.5f);
+ transform.set_rc(3, 1, 2.5f);
+ transform.set_rc(3, 2, 4.5f);
+ transform.set_rc(3, 3, 8.5f);
+ EXPECT_EQ(expected, transform.MapVector(vector));
+
+ // MapVector with a simple 2d transform.
+ transform = Transform::MakeTranslation(10, 20) * Transform::MakeScale(3, 4);
+ expected.set_z(vector.z());
+ EXPECT_EQ(expected, transform.MapVector(vector));
+
+ transform.EnsureFullMatrixForTesting();
+ EXPECT_EQ(expected, transform.MapVector(vector));
+}
+
+TEST(XFormTest, PreConcatAxisTransform2d) {
+ auto t = Transform::RowMajor(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17);
+ auto axis = AxisTransform2d::FromScaleAndTranslation(Vector2dF(10, 20),
+ Vector2dF(100, 200));
+ auto axis_full =
+ Transform::MakeTranslation(100, 200) * Transform::MakeScale(10, 20);
+ auto t1 = t;
+ t.PreConcat(axis);
+ t1.PreConcat(axis_full);
+ EXPECT_EQ(t, t1);
+}
+
+TEST(XFormTest, PostConcatAxisTransform2d) {
+ auto t = Transform::RowMajor(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17);
+ auto axis = AxisTransform2d::FromScaleAndTranslation(Vector2dF(10, 20),
+ Vector2dF(100, 200));
+ auto axis_full =
+ Transform::MakeTranslation(100, 200) * Transform::MakeScale(10, 20);
+ auto t1 = t;
+ t.PostConcat(axis);
+ t1.PostConcat(axis_full);
+ EXPECT_EQ(t, t1);
+}
+
+TEST(XFormTest, ClampOutput) {
+ double entries[][2] = {
+ // The first entry is used to initialize the transform.
+ // The second entry is used to initialize the object to be mapped.
+ {std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::infinity()},
+ {1, std::numeric_limits<float>::infinity()},
+ {-1, std::numeric_limits<float>::infinity()},
+ {1, -std::numeric_limits<float>::infinity()},
+ {
+ std::numeric_limits<float>::max(),
+ std::numeric_limits<float>::max(),
+ },
+ {
+ std::numeric_limits<float>::lowest(),
+ -std::numeric_limits<float>::infinity(),
+ },
+ };
+
+ for (double* entry : entries) {
+ const float mv = entry[0];
+ const float factor = entry[1];
+
+ auto is_valid_point = [&](const PointF& p) -> bool {
+ return std::isfinite(p.x()) && std::isfinite(p.y());
+ };
+ auto is_valid_point3 = [&](const Point3F& p) -> bool {
+ return std::isfinite(p.x()) && std::isfinite(p.y()) &&
+ std::isfinite(p.z());
+ };
+ auto is_valid_vector2 = [&](const Vector2dF& v) -> bool {
+ return std::isfinite(v.x()) && std::isfinite(v.y());
+ };
+ auto is_valid_vector3 = [&](const Vector3dF& v) -> bool {
+ return std::isfinite(v.x()) && std::isfinite(v.y()) &&
+ std::isfinite(v.z());
+ };
+ auto is_valid_rect = [&](const RectF& r) -> bool {
+ return is_valid_point(r.origin()) && std::isfinite(r.width()) &&
+ std::isfinite(r.height());
+ };
+ auto is_valid_array = [&](const float* a, size_t size) -> bool {
+ for (size_t i = 0; i < size; i++) {
+ if (!std::isfinite(a[i]))
+ return false;
+ }
+ return true;
+ };
+
+ auto test = [&](const Transform& m) {
+ SCOPED_TRACE(base::StringPrintf("m: %s factor: %lg", m.ToString().c_str(),
+ factor));
+ auto p = m.MapPoint(PointF(factor, factor));
+ EXPECT_TRUE(is_valid_point(p)) << p.ToString();
+
+ auto p3 = m.MapPoint(Point3F(factor, factor, factor));
+ EXPECT_TRUE(is_valid_point3(p3)) << p3.ToString();
+
+ auto r = m.MapRect(RectF(factor, factor, factor, factor));
+ EXPECT_TRUE(is_valid_rect(r)) << r.ToString();
+
+ auto v3 = m.MapVector(Vector3dF(factor, factor, factor));
+ EXPECT_TRUE(is_valid_vector3(v3)) << v3.ToString();
+
+ float v4[4] = {factor, factor, factor, factor};
+ m.TransformVector4(v4);
+ EXPECT_TRUE(is_valid_array(v4, 4));
+
+ auto v2 = m.To2dTranslation();
+ EXPECT_TRUE(is_valid_vector2(v2)) << v2.ToString();
+ v2 = m.To2dScale();
+ EXPECT_TRUE(is_valid_vector2(v2)) << v2.ToString();
+
+ v3 = m.To3dTranslation();
+ EXPECT_TRUE(is_valid_vector3(v3)) << v3.ToString();
+ };
+
+ test(Transform::ColMajor(mv, mv, mv, mv, mv, mv, mv, mv, mv, mv, mv, mv, mv,
+ mv, mv, mv));
+ test(Transform::MakeTranslation(mv, mv));
+ }
+}
+
+constexpr float kProjectionClampedBigNumber =
+ 1 << (std::numeric_limits<float>::digits - 1);
+
+// This test also demonstrates the relationship between ProjectPoint() and
+// MapPoint().
+TEST(XFormTest, ProjectPoint) {
+ Transform transform;
+ PointF p(1.25f, -3.5f);
+ bool clamped = true;
+ EXPECT_EQ(p, transform.ProjectPoint(p));
+ EXPECT_EQ(p, transform.ProjectPoint(p, &clamped));
+ EXPECT_FALSE(clamped);
+ // MapPoint() and ProjectPoint() are the same with a flat transform.
+ EXPECT_EQ(p, transform.MapPoint(p));
+
+ // ProjectPoint with simple 2d transform.
+ transform = Transform::MakeTranslation(10, 20) * Transform::MakeScale(3, 4);
+ clamped = true;
+ gfx::PointF projected = transform.ProjectPoint(p, &clamped);
+ EXPECT_EQ(PointF(13.75f, 6.f), projected);
+ EXPECT_FALSE(clamped);
+ // MapPoint() and ProjectPoint() are the same with a flat transform.
+ EXPECT_EQ(projected, transform.MapPoint(p));
+
+ clamped = true;
+ transform.EnsureFullMatrixForTesting();
+ EXPECT_EQ(projected, transform.ProjectPoint(p, &clamped));
+ EXPECT_FALSE(clamped);
+ EXPECT_EQ(projected, transform.MapPoint(p));
+
+ // Set scale z to 0.
+ transform.set_rc(2, 2, 0);
+ clamped = true;
+ projected = transform.ProjectPoint(p, &clamped);
+ EXPECT_EQ(PointF(), projected);
+ EXPECT_TRUE(clamped);
+ // MapPoint() still produces the original result.
+ EXPECT_EQ(PointF(13.75f, 6.f), transform.MapPoint(p));
+
+ // Normally (except the last case below), t.ProjectPoint() is equivalent to
+ // inverse(flatten(inverse(t))).MapPoint().
+ auto projection_transform = [](const Transform& t) {
+ auto flat = t.GetCheckedInverse();
+ flat.Flatten();
+ return flat.GetCheckedInverse();
+ };
+
+ transform.MakeIdentity();
+ transform.RotateAboutYAxis(60);
+ clamped = true;
+ projected = transform.ProjectPoint(p, &clamped);
+ EXPECT_EQ(PointF(2.5f, -3.5f), projected);
+ EXPECT_FALSE(clamped);
+ EXPECT_EQ(PointF(0.625f, -3.5f), transform.MapPoint(p));
+
+ EXPECT_EQ(projected, projection_transform(transform).MapPoint(p));
+ EXPECT_EQ(projected, projection_transform(transform).ProjectPoint(p));
+
+ transform.ApplyPerspectiveDepth(10);
+ clamped = true;
+ projected = transform.ProjectPoint(p, &clamped);
+ EXPECT_POINTF_NEAR(PointF(3.19f, -4.47f), projected, 0.01f);
+ EXPECT_FALSE(clamped);
+ EXPECT_EQ(PointF(0.625f, -3.5f), transform.MapPoint(p));
+
+ EXPECT_POINTF_NEAR(projected, projection_transform(transform).MapPoint(p),
+ 1e-5f);
+ EXPECT_POINTF_NEAR(projected, projection_transform(transform).ProjectPoint(p),
+ 1e-5f);
+
+ // With a small perspective, the ray doesn't intersect the destination plane.
+ transform.ApplyPerspectiveDepth(2);
+ clamped = false;
+ projected = transform.ProjectPoint(p, &clamped);
+ EXPECT_TRUE(clamped);
+ EXPECT_EQ(projected.x(), kProjectionClampedBigNumber);
+ EXPECT_EQ(projected.y(), -kProjectionClampedBigNumber);
+ EXPECT_EQ(PointF(0.625f, -3.5f), transform.MapPoint(p));
+ // In this case, MapPoint() returns a point behind the eye.
+ EXPECT_POINTF_NEAR(PointF(-8.36014f, 11.7042f),
+ projection_transform(transform).MapPoint(p), 1e-5f);
+ EXPECT_POINTF_NEAR(projected, projection_transform(transform).ProjectPoint(p),
+ 1e-5f);
+}
+
+TEST(XFormTest, ProjectQuad) {
+ auto transform = Transform::MakeTranslation(3.25f, 7.75f);
+ QuadF q(PointF(1.25f, 2.5f), PointF(3.75f, 4.f), PointF(23.f, 45.f),
+ PointF(12.f, 67.f));
+ EXPECT_EQ(QuadF(PointF(4.5f, 10.25f), PointF(7.f, 11.75f),
+ PointF(26.25f, 52.75f), PointF(15.25f, 74.75f)),
+ transform.ProjectQuad(q));
+
+ transform.set_rc(2, 2, 0);
+ EXPECT_EQ(QuadF(), transform.ProjectQuad(q));
+
+ transform.MakeIdentity();
+ transform.RotateAboutYAxis(60);
+ EXPECT_EQ(QuadF(PointF(2.5f, 2.5f), PointF(7.5f, 4.f), PointF(46.f, 45.f),
+ PointF(24.f, 67.f)),
+ transform.ProjectQuad(q));
+
+ // With a small perspective, all points of |q| are clamped, and the
+ // projected result is an empty quad.
+ transform.ApplyPerspectiveDepth(2);
+ EXPECT_EQ(QuadF(), transform.ProjectQuad(q));
+
+ // Change the quad so that 2 points are clamped.
+ q.set_p1(PointF(-1.25f, -2.5f));
+ q.set_p2(PointF(-3.75f, 4.f));
+ q.set_p3(PointF(23.f, -45.f));
+ QuadF q1 = transform.ProjectQuad(q);
+ EXPECT_POINTF_NEAR(PointF(-1.2f, -1.2f), q1.p1(), 0.01f);
+ EXPECT_POINTF_NEAR(PointF(-1.77f, 0.94f), q1.p2(), 0.01f);
+ EXPECT_EQ(q1.p3().x(), kProjectionClampedBigNumber);
+ EXPECT_EQ(q1.p3().y(), -kProjectionClampedBigNumber);
+ EXPECT_EQ(q1.p4().x(), kProjectionClampedBigNumber);
+ EXPECT_EQ(q1.p4().y(), kProjectionClampedBigNumber);
+}
+
+TEST(XFormTest, ToString) {
+ auto zeros =
+ Transform::ColMajor(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ EXPECT_EQ("[ 0 0 0 0\n 0 0 0 0\n 0 0 0 0\n 0 0 0 0 ]\n", zeros.ToString());
+ EXPECT_EQ("[ 0 0 0 0\n 0 0 0 0\n 0 0 0 0\n 0 0 0 0 ]\n(degenerate)",
+ zeros.ToDecomposedString());
+
+ Transform identity;
+ EXPECT_EQ("[ 1 0 0 0\n 0 1 0 0\n 0 0 1 0\n 0 0 0 1 ]\n",
+ identity.ToString());
+ EXPECT_EQ("identity", identity.ToDecomposedString());
+
+ Transform translation;
+ translation.Translate3d(3, 5, 7);
+ EXPECT_EQ("[ 1 0 0 3\n 0 1 0 5\n 0 0 1 7\n 0 0 0 1 ]\n",
+ translation.ToString());
+ EXPECT_EQ("translate: 3,5,7", translation.ToDecomposedString());
+
+ auto transform = Transform::ColMajor(1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8,
+ 1e20, 1e-20, 1.0 / 3.0, 0, 0, 0, 0, 1);
+ EXPECT_EQ(
+ "[ 1.1 5.5 1e+20 0\n 2.2 6.6 1e-20 0\n 3.3 7.7 0.333333 0\n"
+ " 4.4 8.8 0 1 ]\n",
+ transform.ToString());
+ EXPECT_EQ(
+ "translate: +0 +0 +0\n"
+ "scale: -4.11582 -2.88048 -4.08248e+19\n"
+ "skew: +3.87836 +0.654654 +2.13809\n"
+ "perspective: -6.66667e-21 -1 +2 +1\n"
+ "quaternion: -0.582925 +0.603592 +0.518949 +0.162997\n",
+ transform.ToDecomposedString());
+}
+
+TEST(XFormTest, Is2dProportionalUpscaleAndOr2dTranslation) {
+ Transform transform;
+ EXPECT_TRUE(transform.Is2dProportionalUpscaleAndOr2dTranslation());
+
+ transform.MakeIdentity();
+ transform.Translate(10, 0);
+ EXPECT_TRUE(transform.Is2dProportionalUpscaleAndOr2dTranslation());
+
+ transform.MakeIdentity();
+ transform.Scale(1.3);
+ EXPECT_TRUE(transform.Is2dProportionalUpscaleAndOr2dTranslation());
+
+ transform.MakeIdentity();
+ transform.Translate(0, -20);
+ transform.Scale(1.7);
+ EXPECT_TRUE(transform.Is2dProportionalUpscaleAndOr2dTranslation());
+
+ transform.MakeIdentity();
+ transform.Scale(0.99);
+ EXPECT_FALSE(transform.Is2dProportionalUpscaleAndOr2dTranslation());
+
+ transform.MakeIdentity();
+ transform.Translate3d(0, 0, 1);
+ EXPECT_FALSE(transform.Is2dProportionalUpscaleAndOr2dTranslation());
+
+ transform.MakeIdentity();
+ transform.Rotate(40);
+ EXPECT_FALSE(transform.Is2dProportionalUpscaleAndOr2dTranslation());
+
+ transform.MakeIdentity();
+ transform.SkewX(30);
+ EXPECT_FALSE(transform.Is2dProportionalUpscaleAndOr2dTranslation());
+}
+
+TEST(XFormTest, Creates3d) {
+ EXPECT_FALSE(Transform().Creates3d());
+ EXPECT_FALSE(Transform::MakeTranslation(1, 2).Creates3d());
+
+ Transform transform;
+ transform.ApplyPerspectiveDepth(100);
+ EXPECT_FALSE(transform.Creates3d());
+ transform.Scale3d(2, 3, 4);
+ EXPECT_FALSE(transform.Creates3d());
+ transform.Translate3d(1, 2, 3);
+ EXPECT_TRUE(transform.Creates3d());
+
+ transform.MakeIdentity();
+ transform.RotateAboutYAxis(20);
+ EXPECT_TRUE(transform.Creates3d());
+}
+
+TEST(XFormTest, ApplyTransformOrigin) {
+ // (0,0,0) is a fixed point of this scale.
+ // (1,1,1) should be scaled appropriately.
+ Transform transform;
+ transform.Scale3d(2, 3, 4);
+ EXPECT_EQ(Point3F(0, 0, 0), transform.MapPoint(Point3F(0, 0, 0)));
+ EXPECT_EQ(Point3F(2, 3, -4), transform.MapPoint(Point3F(1, 1, -1)));
+
+ // With the transform origin applied, (1,2,3) is the fixed point.
+ // (0,0,0) should be scaled according to its distance from (1,2,3).
+ transform.ApplyTransformOrigin(1, 2, 3);
+ EXPECT_EQ(Point3F(1, 2, 3), transform.MapPoint(Point3F(1, 2, 3)));
+ EXPECT_EQ(Point3F(-1, -4, -9), transform.MapPoint(Point3F(0, 0, 0)));
+
+ transform = GetTestMatrix1();
+ Vector3dF origin(5.f, 6.f, 7.f);
+ Transform with_origin = transform;
+ Point3F p(41.f, 43.f, 47.f);
+ with_origin.ApplyTransformOrigin(origin.x(), origin.y(), origin.z());
+ EXPECT_POINT3F_EQ(transform.MapPoint(p - origin) + origin,
+ with_origin.MapPoint(p));
+}
+
+TEST(XFormTest, Zoom) {
+ Transform transform = GetTestMatrix1();
+ auto zoomed = transform;
+ zoomed.Zoom(2.f);
+ Point3F p(41.f, 43.f, 47.f);
+ Point3F expected = p;
+ expected.Scale(0.5f, 0.5f, 0.5f);
+ expected = transform.MapPoint(expected);
+ expected.Scale(2.f, 2.f, 2.f);
+ EXPECT_POINT3F_EQ(expected, zoomed.MapPoint(p));
+}
+
+TEST(XFormTest, ApproximatelyEqual) {
+ EXPECT_TRUE(Transform().ApproximatelyEqual(Transform()));
+ EXPECT_TRUE(Transform().ApproximatelyEqual(Transform(), 0));
+ EXPECT_TRUE(GetTestMatrix1().ApproximatelyEqual(GetTestMatrix1()));
+ EXPECT_TRUE(GetTestMatrix1().ApproximatelyEqual(GetTestMatrix1(), 0));
+
+ Transform t1 = Transform::MakeTranslation(0.9, -0.9);
+ Transform t2 = Transform::MakeScale(1.099, 0.901);
+ EXPECT_TRUE(t1.ApproximatelyEqual(t2));
+ EXPECT_FALSE(t1.ApproximatelyEqual(t2, 0.8f, 0.2f, 0.0f));
+ EXPECT_FALSE(t1.ApproximatelyEqual(t2, 1.0f, 0.01f, 0.0f));
+ EXPECT_FALSE(t1.ApproximatelyEqual(t2, 1.0f, 0.01f, 0.05f));
+ EXPECT_TRUE(t1.ApproximatelyEqual(t2, 1.0f, 0.2f, 1.f));
+ EXPECT_TRUE(t1.ApproximatelyEqual(t2, 1.0f, 0.2f, 0.1f));
+
+ for (int r = 0; r < 4; r++) {
+ for (int c = 0; c < 4; c++) {
+ t1 = Transform();
+ t1.set_rc(r, c, t1.rc(r, c) + 0.25f);
+ EXPECT_TRUE(t1.ApproximatelyEqual(Transform(), 0.25f));
+ EXPECT_FALSE(t1.ApproximatelyEqual(Transform(), 0.24f));
+ }
+ }
+}
+
} // namespace
} // namespace gfx
diff --git a/ui/gfx/geometry/transform_util.cc b/ui/gfx/geometry/transform_util.cc
index 224598d..f3707fd 100644
--- a/ui/gfx/geometry/transform_util.cc
+++ b/ui/gfx/geometry/transform_util.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,10 +6,10 @@
#include <algorithm>
#include <cmath>
+#include <ostream>
#include <string>
#include "base/check.h"
-#include "base/strings/stringprintf.h"
#include "ui/gfx/geometry/point3_f.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
@@ -18,302 +18,14 @@
namespace {
-SkScalar Length3(SkScalar v[3]) {
- double vd[3] = {v[0], v[1], v[2]};
- return SkDoubleToScalar(
- std::sqrt(vd[0] * vd[0] + vd[1] * vd[1] + vd[2] * vd[2]));
-}
-
template <int n>
-SkScalar Dot(const SkScalar* a, const SkScalar* b) {
- double total = 0.0;
- for (int i = 0; i < n; ++i)
- total += a[i] * b[i];
- return SkDoubleToScalar(total);
-}
-
-template <int n>
-void Combine(SkScalar* out,
- const SkScalar* a,
- const SkScalar* b,
+void Combine(double* out,
+ const double* a,
+ const double* b,
double scale_a,
double scale_b) {
for (int i = 0; i < n; ++i)
- out[i] = SkDoubleToScalar(a[i] * scale_a + b[i] * scale_b);
-}
-
-void Cross3(SkScalar out[3], SkScalar a[3], SkScalar b[3]) {
- SkScalar x = a[1] * b[2] - a[2] * b[1];
- SkScalar y = a[2] * b[0] - a[0] * b[2];
- SkScalar z = a[0] * b[1] - a[1] * b[0];
- out[0] = x;
- out[1] = y;
- out[2] = z;
-}
-
-SkScalar Round(SkScalar n) {
- return SkDoubleToScalar(std::floor(double{n} + 0.5));
-}
-
-// Returns false if the matrix cannot be normalized.
-bool Normalize(skia::Matrix44& m) {
- if (m.get(3, 3) == 0.0)
- // Cannot normalize.
- return false;
-
- SkScalar scale = SK_Scalar1 / m.get(3, 3);
- for (int i = 0; i < 4; i++)
- for (int j = 0; j < 4; j++)
- m.set(i, j, m.get(i, j) * scale);
-
- return true;
-}
-
-skia::Matrix44 BuildPerspectiveMatrix(const DecomposedTransform& decomp) {
- skia::Matrix44 matrix(skia::Matrix44::kIdentity_Constructor);
-
- for (int i = 0; i < 4; i++)
- matrix.setDouble(3, i, decomp.perspective[i]);
- return matrix;
-}
-
-skia::Matrix44 BuildTranslationMatrix(const DecomposedTransform& decomp) {
- skia::Matrix44 matrix(skia::Matrix44::kUninitialized_Constructor);
- // Implicitly calls matrix.setIdentity()
- matrix.setTranslate(SkDoubleToScalar(decomp.translate[0]),
- SkDoubleToScalar(decomp.translate[1]),
- SkDoubleToScalar(decomp.translate[2]));
- return matrix;
-}
-
-skia::Matrix44 BuildSnappedTranslationMatrix(DecomposedTransform decomp) {
- decomp.translate[0] = Round(decomp.translate[0]);
- decomp.translate[1] = Round(decomp.translate[1]);
- decomp.translate[2] = Round(decomp.translate[2]);
- return BuildTranslationMatrix(decomp);
-}
-
-skia::Matrix44 BuildRotationMatrix(const DecomposedTransform& decomp) {
- return Transform(decomp.quaternion).matrix();
-}
-
-skia::Matrix44 BuildSnappedRotationMatrix(const DecomposedTransform& decomp) {
- // Create snapped rotation.
- skia::Matrix44 rotation_matrix = BuildRotationMatrix(decomp);
- for (int i = 0; i < 3; ++i) {
- for (int j = 0; j < 3; ++j) {
- SkScalar value = rotation_matrix.get(i, j);
- // Snap values to -1, 0 or 1.
- if (value < -0.5f) {
- value = -1.0f;
- } else if (value > 0.5f) {
- value = 1.0f;
- } else {
- value = 0.0f;
- }
- rotation_matrix.set(i, j, value);
- }
- }
- return rotation_matrix;
-}
-
-skia::Matrix44 BuildSkewMatrix(const DecomposedTransform& decomp) {
- skia::Matrix44 matrix(skia::Matrix44::kIdentity_Constructor);
-
- skia::Matrix44 temp(skia::Matrix44::kIdentity_Constructor);
- if (decomp.skew[2]) {
- temp.setDouble(1, 2, decomp.skew[2]);
- matrix.preConcat(temp);
- }
-
- if (decomp.skew[1]) {
- temp.setDouble(1, 2, 0);
- temp.setDouble(0, 2, decomp.skew[1]);
- matrix.preConcat(temp);
- }
-
- if (decomp.skew[0]) {
- temp.setDouble(0, 2, 0);
- temp.setDouble(0, 1, decomp.skew[0]);
- matrix.preConcat(temp);
- }
- return matrix;
-}
-
-skia::Matrix44 BuildScaleMatrix(const DecomposedTransform& decomp) {
- skia::Matrix44 matrix(skia::Matrix44::kUninitialized_Constructor);
- matrix.setScale(SkDoubleToScalar(decomp.scale[0]),
- SkDoubleToScalar(decomp.scale[1]),
- SkDoubleToScalar(decomp.scale[2]));
- return matrix;
-}
-
-skia::Matrix44 BuildSnappedScaleMatrix(DecomposedTransform decomp) {
- decomp.scale[0] = Round(decomp.scale[0]);
- decomp.scale[1] = Round(decomp.scale[1]);
- decomp.scale[2] = Round(decomp.scale[2]);
- return BuildScaleMatrix(decomp);
-}
-
-Transform ComposeTransform(const skia::Matrix44& perspective,
- const skia::Matrix44& translation,
- const skia::Matrix44& rotation,
- const skia::Matrix44& skew,
- const skia::Matrix44& scale) {
- skia::Matrix44 matrix(skia::Matrix44::kIdentity_Constructor);
-
- matrix.preConcat(perspective);
- matrix.preConcat(translation);
- matrix.preConcat(rotation);
- matrix.preConcat(skew);
- matrix.preConcat(scale);
-
- Transform to_return;
- to_return.matrix() = matrix;
- return to_return;
-}
-
-bool CheckViewportPointMapsWithinOnePixel(const Point& point,
- const Transform& transform) {
- auto point_original = Point3F(PointF(point));
- auto point_transformed = Point3F(PointF(point));
-
- // Can't use TransformRect here since it would give us the axis-aligned
- // bounding rect of the 4 points in the initial rectable which is not what we
- // want.
- transform.TransformPoint(&point_transformed);
-
- if ((point_transformed - point_original).Length() > 1.f) {
- // The changed distance should not be more than 1 pixel.
- return false;
- }
- return true;
-}
-
-bool CheckTransformsMapsIntViewportWithinOnePixel(const Rect& viewport,
- const Transform& original,
- const Transform& snapped) {
- Transform original_inv(Transform::kSkipInitialization);
- bool invertible = true;
- invertible &= original.GetInverse(&original_inv);
- DCHECK(invertible) << "Non-invertible transform, cannot snap.";
-
- Transform combined = snapped * original_inv;
-
- return CheckViewportPointMapsWithinOnePixel(viewport.origin(), combined) &&
- CheckViewportPointMapsWithinOnePixel(viewport.top_right(), combined) &&
- CheckViewportPointMapsWithinOnePixel(viewport.bottom_left(),
- combined) &&
- CheckViewportPointMapsWithinOnePixel(viewport.bottom_right(),
- combined);
-}
-
-bool Is2dTransform(const Transform& transform) {
- const skia::Matrix44 matrix = transform.matrix();
- if (matrix.hasPerspective())
- return false;
-
- return matrix.get(2, 0) == 0 && matrix.get(2, 1) == 0 &&
- matrix.get(0, 2) == 0 && matrix.get(1, 2) == 0 &&
- matrix.get(2, 2) == 1 && matrix.get(3, 2) == 0 &&
- matrix.get(2, 3) == 0;
-}
-
-bool Decompose2DTransform(DecomposedTransform* decomp,
- const Transform& transform) {
- if (!Is2dTransform(transform)) {
- return false;
- }
-
- const skia::Matrix44 matrix = transform.matrix();
- double m11 = matrix.getDouble(0, 0);
- double m21 = matrix.getDouble(0, 1);
- double m12 = matrix.getDouble(1, 0);
- double m22 = matrix.getDouble(1, 1);
-
- double determinant = m11 * m22 - m12 * m21;
- // Test for matrix being singular.
- if (determinant == 0) {
- return false;
- }
-
- // Translation transform.
- // [m11 m21 0 m41] [1 0 0 Tx] [m11 m21 0 0]
- // [m12 m22 0 m42] = [0 1 0 Ty] [m12 m22 0 0]
- // [ 0 0 1 0 ] [0 0 1 0 ] [ 0 0 1 0]
- // [ 0 0 0 1 ] [0 0 0 1 ] [ 0 0 0 1]
- decomp->translate[0] = matrix.get(0, 3);
- decomp->translate[1] = matrix.get(1, 3);
-
- // For the remainder of the decomposition process, we can focus on the upper
- // 2x2 submatrix
- // [m11 m21] = [cos(R) -sin(R)] [1 K] [Sx 0 ]
- // [m12 m22] [sin(R) cos(R)] [0 1] [0 Sy]
- // = [Sx*cos(R) Sy*(K*cos(R) - sin(R))]
- // [Sx*sin(R) Sy*(K*sin(R) + cos(R))]
-
- // Determine sign of the x and y scale.
- if (determinant < 0) {
- // If the determinant is negative, we need to flip either the x or y scale.
- // Flipping both is equivalent to rotating by 180 degrees.
- if (m11 < m22) {
- decomp->scale[0] *= -1;
- } else {
- decomp->scale[1] *= -1;
- }
- }
-
- // X Scale.
- // m11^2 + m12^2 = Sx^2*(cos^2(R) + sin^2(R)) = Sx^2.
- // Sx = +/-sqrt(m11^2 + m22^2)
- decomp->scale[0] *= sqrt(m11 * m11 + m12 * m12);
- m11 /= decomp->scale[0];
- m12 /= decomp->scale[0];
-
- // Post normalization, the submatrix is now of the form:
- // [m11 m21] = [cos(R) Sy*(K*cos(R) - sin(R))]
- // [m12 m22] [sin(R) Sy*(K*sin(R) + cos(R))]
-
- // XY Shear.
- // m11 * m21 + m12 * m22 = Sy*K*cos^2(R) - Sy*sin(R)*cos(R) +
- // Sy*K*sin^2(R) + Sy*cos(R)*sin(R)
- // = Sy*K
- double scaledShear = m11 * m21 + m12 * m22;
- m21 -= m11 * scaledShear;
- m22 -= m12 * scaledShear;
-
- // Post normalization, the submatrix is now of the form:
- // [m11 m21] = [cos(R) -Sy*sin(R)]
- // [m12 m22] [sin(R) Sy*cos(R)]
-
- // Y Scale.
- // Similar process to determining x-scale.
- decomp->scale[1] *= sqrt(m21 * m21 + m22 * m22);
- m21 /= decomp->scale[1];
- m22 /= decomp->scale[1];
- decomp->skew[0] = scaledShear / decomp->scale[1];
-
- // Rotation transform.
- // [1-2(yy+zz) 2(xy-zw) 2(xz+yw) ] [cos(R) -sin(R) 0]
- // [2(xy+zw) 1-2(xx+zz) 2(yz-xw) ] = [sin(R) cos(R) 0]
- // [2(xz-yw) 2*(yz+xw) 1-2(xx+yy)] [ 0 0 1]
- // Comparing terms, we can conclude that x = y = 0.
- // [1-2zz -2zw 0] [cos(R) -sin(R) 0]
- // [ 2zw 1-2zz 0] = [sin(R) cos(R) 0]
- // [ 0 0 1] [ 0 0 1]
- // cos(R) = 1 - 2*z^2
- // From the double angle formula: cos(2a) = 1 - 2 sin(a)^2
- // cos(R) = 1 - 2*sin(R/2)^2 = 1 - 2*z^2 ==> z = sin(R/2)
- // sin(R) = 2*z*w
- // But sin(2a) = 2 sin(a) cos(a)
- // sin(R) = 2 sin(R/2) cos(R/2) = 2*z*w ==> w = cos(R/2)
- double angle = atan2(m12, m11);
- decomp->quaternion.set_x(0);
- decomp->quaternion.set_y(0);
- decomp->quaternion.set_z(sin(0.5 * angle));
- decomp->quaternion.set_w(cos(0.5 * angle));
-
- return true;
+ out[i] = a[i] * scale_a + b[i] * scale_b;
}
} // namespace
@@ -325,14 +37,6 @@
return transform;
}
-DecomposedTransform::DecomposedTransform() {
- translate[0] = translate[1] = translate[2] = 0.0;
- scale[0] = scale[1] = scale[2] = 1.0;
- skew[0] = skew[1] = skew[2] = 0.0;
- perspective[0] = perspective[1] = perspective[2] = 0.0;
- perspective[3] = 1.0;
-}
-
DecomposedTransform BlendDecomposedTransforms(const DecomposedTransform& to,
const DecomposedTransform& from,
double progress) {
@@ -347,232 +51,39 @@
return out;
}
-// Taken from http://www.w3.org/TR/css3-transforms/.
-// TODO(crbug/937296): This implementation is virtually identical to the
-// implementation in blink::TransformationMatrix with the main difference being
-// the representation of the underlying matrix. These implementations should be
-// consolidated.
-bool DecomposeTransform(DecomposedTransform* decomp,
- const Transform& transform) {
- if (!decomp)
- return false;
+DecomposedTransform AccumulateDecomposedTransforms(
+ const DecomposedTransform& a,
+ const DecomposedTransform& b) {
+ DecomposedTransform out;
- if (Decompose2DTransform(decomp, transform))
- return true;
+ // Translate is a simple addition.
+ for (size_t i = 0; i < std::size(a.translate); i++)
+ out.translate[i] = a.translate[i] + b.translate[i];
- // We'll operate on a copy of the matrix.
- skia::Matrix44 matrix = transform.matrix();
+ // Scale is accumulated using 1-based addition.
+ for (size_t i = 0; i < std::size(a.scale); i++)
+ out.scale[i] = a.scale[i] + b.scale[i] - 1;
- // If we cannot normalize the matrix, then bail early as we cannot decompose.
- if (!Normalize(matrix))
- return false;
+ // Skew can be added.
+ for (size_t i = 0; i < std::size(a.skew); i++)
+ out.skew[i] = a.skew[i] + b.skew[i];
- skia::Matrix44 perspectiveMatrix = matrix;
+ // We sum the perspective components; note that w is 1-based.
+ for (size_t i = 0; i < std::size(a.perspective); i++)
+ out.perspective[i] = a.perspective[i] + b.perspective[i];
+ out.perspective[3] -= 1;
- for (int i = 0; i < 3; ++i)
- perspectiveMatrix.set(3, i, 0.0);
+ // To accumulate quaternions, we multiply them. This is equivalent to 'adding'
+ // the rotations that they represent.
+ out.quaternion = a.quaternion * b.quaternion;
- perspectiveMatrix.set(3, 3, 1.0);
-
- // If the perspective matrix is not invertible, we are also unable to
- // decompose, so we'll bail early. Constant taken from skia::Matrix44::invert.
- if (std::abs(perspectiveMatrix.determinant()) < 1e-8)
- return false;
-
- if (matrix.get(3, 0) != 0.0 || matrix.get(3, 1) != 0.0 ||
- matrix.get(3, 2) != 0.0) {
- // rhs is the right hand side of the equation.
- SkScalar rhs[4] = {matrix.get(3, 0), matrix.get(3, 1), matrix.get(3, 2),
- matrix.get(3, 3)};
-
- // Solve the equation by inverting perspectiveMatrix and multiplying
- // rhs by the inverse.
- skia::Matrix44 inversePerspectiveMatrix(
- skia::Matrix44::kUninitialized_Constructor);
- if (!perspectiveMatrix.invert(&inversePerspectiveMatrix))
- return false;
-
- skia::Matrix44 transposedInversePerspectiveMatrix =
- inversePerspectiveMatrix;
-
- transposedInversePerspectiveMatrix.transpose();
- transposedInversePerspectiveMatrix.mapScalars(rhs);
-
- for (int i = 0; i < 4; ++i)
- decomp->perspective[i] = rhs[i];
-
- } else {
- // No perspective.
- for (int i = 0; i < 3; ++i)
- decomp->perspective[i] = 0.0;
- decomp->perspective[3] = 1.0;
- }
-
- for (int i = 0; i < 3; i++)
- decomp->translate[i] = matrix.get(i, 3);
-
- // Copy of matrix is stored in column major order to facilitate column-level
- // operations.
- SkScalar column[3][3];
- for (int i = 0; i < 3; i++)
- for (int j = 0; j < 3; ++j)
- column[i][j] = matrix.get(j, i);
-
- // Compute X scale factor and normalize first column.
- decomp->scale[0] = Length3(column[0]);
- if (decomp->scale[0] != 0.0) {
- column[0][0] /= decomp->scale[0];
- column[0][1] /= decomp->scale[0];
- column[0][2] /= decomp->scale[0];
- }
-
- // Compute XY shear factor and make 2nd column orthogonal to 1st.
- decomp->skew[0] = Dot<3>(column[0], column[1]);
- Combine<3>(column[1], column[1], column[0], 1.0, -decomp->skew[0]);
-
- // Now, compute Y scale and normalize 2nd column.
- decomp->scale[1] = Length3(column[1]);
- if (decomp->scale[1] != 0.0) {
- column[1][0] /= decomp->scale[1];
- column[1][1] /= decomp->scale[1];
- column[1][2] /= decomp->scale[1];
- }
-
- decomp->skew[0] /= decomp->scale[1];
-
- // Compute XZ and YZ shears, orthogonalize the 3rd column.
- decomp->skew[1] = Dot<3>(column[0], column[2]);
- Combine<3>(column[2], column[2], column[0], 1.0, -decomp->skew[1]);
- decomp->skew[2] = Dot<3>(column[1], column[2]);
- Combine<3>(column[2], column[2], column[1], 1.0, -decomp->skew[2]);
-
- // Next, get Z scale and normalize the 3rd column.
- decomp->scale[2] = Length3(column[2]);
- if (decomp->scale[2] != 0.0) {
- column[2][0] /= decomp->scale[2];
- column[2][1] /= decomp->scale[2];
- column[2][2] /= decomp->scale[2];
- }
-
- decomp->skew[1] /= decomp->scale[2];
- decomp->skew[2] /= decomp->scale[2];
-
- // At this point, the matrix is orthonormal.
- // Check for a coordinate system flip. If the determinant
- // is -1, then negate the matrix and the scaling factors.
- // TODO(kevers): This is inconsistent from the 2D specification, in which
- // only 1 axis is flipped when the determinant is negative. Verify if it is
- // correct to flip all of the scales and matrix elements, as this introduces
- // rotation for the simple case of a single axis scale inversion.
- SkScalar pdum3[3];
- Cross3(pdum3, column[1], column[2]);
- if (Dot<3>(column[0], pdum3) < 0) {
- for (int i = 0; i < 3; i++) {
- decomp->scale[i] *= -1.0;
- for (int j = 0; j < 3; ++j)
- column[i][j] *= -1.0;
- }
- }
-
- // See https://en.wikipedia.org/wiki/Rotation_matrix#Quaternion.
- // Note: deviating from spec (http://www.w3.org/TR/css3-transforms/)
- // which has a degenerate case of zero off-diagonal elements in the
- // orthonormal matrix, which leads to errors in determining the sign
- // of the quaternions.
- double q_xx = column[0][0];
- double q_xy = column[1][0];
- double q_xz = column[2][0];
- double q_yx = column[0][1];
- double q_yy = column[1][1];
- double q_yz = column[2][1];
- double q_zx = column[0][2];
- double q_zy = column[1][2];
- double q_zz = column[2][2];
-
- double r, s, t, x, y, z, w;
- t = q_xx + q_yy + q_zz;
- if (t > 0) {
- r = std::sqrt(1.0 + t);
- s = 0.5 / r;
- w = 0.5 * r;
- x = (q_zy - q_yz) * s;
- y = (q_xz - q_zx) * s;
- z = (q_yx - q_xy) * s;
- } else if (q_xx > q_yy && q_xx > q_zz) {
- r = std::sqrt(1.0 + q_xx - q_yy - q_zz);
- s = 0.5 / r;
- x = 0.5 * r;
- y = (q_xy + q_yx) * s;
- z = (q_xz + q_zx) * s;
- w = (q_zy - q_yz) * s;
- } else if (q_yy > q_zz) {
- r = std::sqrt(1.0 - q_xx + q_yy - q_zz);
- s = 0.5 / r;
- x = (q_xy + q_yx) * s;
- y = 0.5 * r;
- z = (q_yz + q_zy) * s;
- w = (q_xz - q_zx) * s;
- } else {
- r = std::sqrt(1.0 - q_xx - q_yy + q_zz);
- s = 0.5 / r;
- x = (q_xz + q_zx) * s;
- y = (q_yz + q_zy) * s;
- z = 0.5 * r;
- w = (q_yx - q_xy) * s;
- }
-
- decomp->quaternion.set_x(SkDoubleToScalar(x));
- decomp->quaternion.set_y(SkDoubleToScalar(y));
- decomp->quaternion.set_z(SkDoubleToScalar(z));
- decomp->quaternion.set_w(SkDoubleToScalar(w));
-
- return true;
+ return out;
}
-// Taken from http://www.w3.org/TR/css3-transforms/.
-Transform ComposeTransform(const DecomposedTransform& decomp) {
- skia::Matrix44 perspective = BuildPerspectiveMatrix(decomp);
- skia::Matrix44 translation = BuildTranslationMatrix(decomp);
- skia::Matrix44 rotation = BuildRotationMatrix(decomp);
- skia::Matrix44 skew = BuildSkewMatrix(decomp);
- skia::Matrix44 scale = BuildScaleMatrix(decomp);
-
- return ComposeTransform(perspective, translation, rotation, skew, scale);
-}
-
-bool SnapTransform(Transform* out,
- const Transform& transform,
- const Rect& viewport) {
- DecomposedTransform decomp;
- DecomposeTransform(&decomp, transform);
-
- skia::Matrix44 rotation_matrix = BuildSnappedRotationMatrix(decomp);
- skia::Matrix44 translation = BuildSnappedTranslationMatrix(decomp);
- skia::Matrix44 scale = BuildSnappedScaleMatrix(decomp);
-
- // Rebuild matrices for other unchanged components.
- skia::Matrix44 perspective = BuildPerspectiveMatrix(decomp);
-
- // Completely ignore the skew.
- skia::Matrix44 skew(skia::Matrix44::kIdentity_Constructor);
-
- // Get full transform.
- Transform snapped =
- ComposeTransform(perspective, translation, rotation_matrix, skew, scale);
-
- // Verify that viewport is not moved unnaturally.
- bool snappable = CheckTransformsMapsIntViewportWithinOnePixel(
- viewport, transform, snapped);
- if (snappable) {
- *out = snapped;
- }
- return snappable;
-}
-
-Transform TransformAboutPivot(const Point& pivot, const Transform& transform) {
+Transform TransformAboutPivot(const PointF& pivot, const Transform& transform) {
Transform result;
result.Translate(pivot.x(), pivot.y());
- result.PreconcatTransform(transform);
+ result.PreConcat(transform);
result.Translate(-pivot.x(), -pivot.y());
return result;
}
@@ -585,54 +96,27 @@
return result;
}
-std::string DecomposedTransform::ToString() const {
- return base::StringPrintf(
- "translate: %+0.4f %+0.4f %+0.4f\n"
- "scale: %+0.4f %+0.4f %+0.4f\n"
- "skew: %+0.4f %+0.4f %+0.4f\n"
- "perspective: %+0.4f %+0.4f %+0.4f %+0.4f\n"
- "quaternion: %+0.4f %+0.4f %+0.4f %+0.4f\n",
- translate[0], translate[1], translate[2], scale[0], scale[1], scale[2],
- skew[0], skew[1], skew[2], perspective[0], perspective[1], perspective[2],
- perspective[3], quaternion.x(), quaternion.y(), quaternion.z(),
- quaternion.w());
-}
-
-Transform OrthoProjectionMatrix(float left,
- float right,
- float bottom,
- float top) {
- // Use the standard formula to map the clipping frustum to the cube from
- // [-1, -1, -1] to [1, 1, 1].
+AxisTransform2d OrthoProjectionTransform(float left,
+ float right,
+ float bottom,
+ float top) {
+ // Use the standard formula to map the clipping frustum to the square from
+ // [-1, -1] to [1, 1].
float delta_x = right - left;
float delta_y = top - bottom;
- Transform proj;
if (!delta_x || !delta_y)
- return proj;
- proj.matrix().set(0, 0, 2.0f / delta_x);
- proj.matrix().set(0, 3, -(right + left) / delta_x);
- proj.matrix().set(1, 1, 2.0f / delta_y);
- proj.matrix().set(1, 3, -(top + bottom) / delta_y);
+ return AxisTransform2d();
- // Z component of vertices is always set to zero as we don't use the depth
- // buffer while drawing.
- proj.matrix().set(2, 2, 0);
-
- return proj;
+ return AxisTransform2d::FromScaleAndTranslation(
+ Vector2dF(2.0f / delta_x, 2.0f / delta_y),
+ Vector2dF(-(right + left) / delta_x, -(top + bottom) / delta_y));
}
-Transform WindowMatrix(int x, int y, int width, int height) {
- Transform canvas;
-
- // Map to window position and scale up to pixel coordinates.
- canvas.Translate3d(x, y, 0);
- canvas.Scale3d(width, height, 0);
-
- // Map from ([-1, -1] to [1, 1]) -> ([0, 0] to [1, 1])
- canvas.Translate3d(0.5, 0.5, 0.5);
- canvas.Scale3d(0.5, 0.5, 0.5);
-
- return canvas;
+AxisTransform2d WindowTransform(int x, int y, int width, int height) {
+ // Map from ([-1, -1] to [1, 1]) -> ([x, y] to [x + width, y + height]).
+ return AxisTransform2d::FromScaleAndTranslation(
+ Vector2dF(width * 0.5f, height * 0.5f),
+ Vector2dF(x + width * 0.5f, y + height * 0.5f));
}
static inline bool NearlyZero(double value) {
@@ -651,22 +135,48 @@
return static_cast<float>(std::sqrt(a * a + b * b + c * c));
}
+absl::optional<Vector2dF> TryComputeTransform2dScaleComponents(
+ const Transform& transform) {
+ if (transform.rc(3, 0) != 0.0f || transform.rc(3, 1) != 0.0f) {
+ return absl::nullopt;
+ }
+
+ float w = transform.rc(3, 3);
+ if (!std::isnormal(w)) {
+ return absl::nullopt;
+ }
+ float w_scale = 1.0f / w;
+
+ // In theory, this shouldn't be using the matrix.getDouble(2, 0) and
+ // .getDouble(1, 0) values; creating a large transfer from input x or
+ // y (in the layer) to output z has no visible difference when the
+ // transform being considered is a transform to device space, since
+ // the resulting z values are ignored. However, ignoring them here
+ // might be risky because it would mean that we would have more
+ // variation in the results under animation of rotateX() or rotateY(),
+ // and we'd be relying more heavily on code to compute correct scales
+ // during animation. Currently some such code only considers the
+ // endpoints, which would become problematic for cases like animation
+ // from rotateY(-60deg) to rotateY(60deg).
+ float x_scale =
+ ScaleOnAxis(transform.rc(0, 0), transform.rc(1, 0), transform.rc(2, 0));
+ float y_scale =
+ ScaleOnAxis(transform.rc(0, 1), transform.rc(1, 1), transform.rc(2, 1));
+ return Vector2dF(x_scale * w_scale, y_scale * w_scale);
+}
+
Vector2dF ComputeTransform2dScaleComponents(const Transform& transform,
float fallback_value) {
- if (transform.HasPerspective())
- return Vector2dF(fallback_value, fallback_value);
- float x_scale = ScaleOnAxis(transform.matrix().getDouble(0, 0),
- transform.matrix().getDouble(1, 0),
- transform.matrix().getDouble(2, 0));
- float y_scale = ScaleOnAxis(transform.matrix().getDouble(0, 1),
- transform.matrix().getDouble(1, 1),
- transform.matrix().getDouble(2, 1));
- return Vector2dF(x_scale, y_scale);
+ absl::optional<Vector2dF> scale =
+ TryComputeTransform2dScaleComponents(transform);
+ if (scale) {
+ return *scale;
+ }
+ return Vector2dF(fallback_value, fallback_value);
}
float ComputeApproximateMaxScale(const Transform& transform) {
- RectF unit(0.f, 0.f, 1.f, 1.f);
- transform.TransformRect(&unit);
+ gfx::RectF unit = transform.MapRect(RectF(0.f, 0.f, 1.f, 1.f));
return std::max(unit.width(), unit.height());
}
diff --git a/ui/gfx/geometry/transform_util.h b/ui/gfx/geometry/transform_util.h
index 235c8e1..3be917e 100644
--- a/ui/gfx/geometry/transform_util.h
+++ b/ui/gfx/geometry/transform_util.h
@@ -1,44 +1,28 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_GEOMETRY_TRANSFORM_UTIL_H_
#define UI_GFX_GEOMETRY_TRANSFORM_UTIL_H_
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/geometry/axis_transform2d.h"
+#include "ui/gfx/geometry/decomposed_transform.h"
#include "ui/gfx/geometry/geometry_skia_export.h"
#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/quaternion.h"
#include "ui/gfx/geometry/transform.h"
namespace gfx {
-class Rect;
class RectF;
// Returns a scale transform at |anchor| point.
GEOMETRY_SKIA_EXPORT Transform GetScaleTransform(const Point& anchor,
float scale);
-// Contains the components of a factored transform. These components may be
-// blended and recomposed.
-struct GEOMETRY_SKIA_EXPORT DecomposedTransform {
- // The default constructor initializes the components in such a way that
- // if used with Compose below, will produce the identity transform.
- DecomposedTransform();
-
- SkScalar translate[3];
- SkScalar scale[3];
- SkScalar skew[3];
- SkScalar perspective[4];
- Quaternion quaternion;
-
- std::string ToString() const;
-
- // Copy and assign are allowed.
-};
-
// Interpolates the decomposed components |to| with |from| using the
-// routines described in http://www.w3.org/TR/css3-3d-transform/.
+// routines described in
+// https://www.w3.org/TR/css-transforms-2/#interpolation-of-decomposed-3d-matrix-values
// |progress| is in the range [0, 1]. If 0 we will return |from|, if 1, we will
// return |to|.
GEOMETRY_SKIA_EXPORT DecomposedTransform
@@ -46,44 +30,43 @@
const DecomposedTransform& from,
double progress);
-// Decomposes this transform into its translation, scale, skew, perspective,
-// and rotation components following the routines detailed in this spec:
-// http://www.w3.org/TR/css3-3d-transforms/.
-GEOMETRY_SKIA_EXPORT bool DecomposeTransform(DecomposedTransform* out,
- const Transform& transform);
-
-// Composes a transform from the given translation, scale, skew, perspective,
-// and rotation components following the routines detailed in this spec:
-// http://www.w3.org/TR/css3-3d-transforms/.
-GEOMETRY_SKIA_EXPORT Transform
-ComposeTransform(const DecomposedTransform& decomp);
-
-GEOMETRY_SKIA_EXPORT bool SnapTransform(Transform* out,
- const Transform& transform,
- const Rect& viewport);
+// Accumulates the decomposed components |to| with |from| using the
+// routines described in
+// https://www.w3.org/TR/css-transforms-2/#combining-transform-lists
+GEOMETRY_SKIA_EXPORT DecomposedTransform
+AccumulateDecomposedTransforms(const DecomposedTransform& to,
+ const DecomposedTransform& from);
// Calculates a transform with a transformed origin. The resulting transform is
// created by composing P * T * P^-1 where P is a constant transform to the new
// origin.
-GEOMETRY_SKIA_EXPORT Transform TransformAboutPivot(const Point& pivot,
+GEOMETRY_SKIA_EXPORT Transform TransformAboutPivot(const PointF& pivot,
const Transform& transform);
// Calculates a transform which would transform |src| to |dst|.
GEOMETRY_SKIA_EXPORT Transform TransformBetweenRects(const RectF& src,
const RectF& dst);
-// Generates projection matrix and returns it as a Transform.
-GEOMETRY_SKIA_EXPORT Transform OrthoProjectionMatrix(float left,
- float right,
- float bottom,
- float top);
+// Returns the 2d axis transform that maps the clipping frustum to the square
+// from [-1, -1] (the original bottom-left corner) to [1, 1] (the original
+// top-right corner).
+GEOMETRY_SKIA_EXPORT AxisTransform2d OrthoProjectionTransform(float left,
+ float right,
+ float bottom,
+ float top);
-// Generates window matrix and returns it as a Transform.
-GEOMETRY_SKIA_EXPORT Transform WindowMatrix(int x,
- int y,
- int width,
- int height);
+// Returns the 2d axis transform that maps from ([-1, -1] .. [1, 1]) to
+// ([x, y] .. [x + width, y + height]).
+GEOMETRY_SKIA_EXPORT AxisTransform2d WindowTransform(int x,
+ int y,
+ int width,
+ int height);
+// Compute 2D scale if possible; return whether it was set.
+GEOMETRY_SKIA_EXPORT absl::optional<Vector2dF>
+TryComputeTransform2dScaleComponents(const Transform& transform);
+
+// Compute 2D scale, and fall back to fallback_value if not possible.
GEOMETRY_SKIA_EXPORT Vector2dF
ComputeTransform2dScaleComponents(const Transform& transform,
float fallback_value);
diff --git a/ui/gfx/geometry/transform_util_unittest.cc b/ui/gfx/geometry/transform_util_unittest.cc
index 87530dd..fbcaaf7 100644
--- a/ui/gfx/geometry/transform_util_unittest.cc
+++ b/ui/gfx/geometry/transform_util_unittest.cc
@@ -1,17 +1,20 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/geometry/transform_util.h"
#include <stddef.h>
+#include <limits>
+#include "base/cxx17_backports.h"
#include "base/numerics/math_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point3_f.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/test/geometry_util.h"
namespace gfx {
namespace {
@@ -27,9 +30,8 @@
const int kOffset = 10;
for (int sign_x = -1; sign_x <= 1; ++sign_x) {
for (int sign_y = -1; sign_y <= 1; ++sign_y) {
- Point test(kAnchor.x() + sign_x * kOffset,
- kAnchor.y() + sign_y * kOffset);
- scale.TransformPoint(&test);
+ Point test = scale.MapPoint(Point(kAnchor.x() + sign_x * kOffset,
+ kAnchor.y() + sign_y * kOffset));
EXPECT_EQ(Point(kAnchor.x() + sign_x * kOffset * kScale,
kAnchor.y() + sign_y * kOffset * kScale),
@@ -38,159 +40,15 @@
}
}
-TEST(TransformUtilTest, SnapRotation) {
- Transform result(Transform::kSkipInitialization);
- Transform transform;
- transform.RotateAboutZAxis(89.99);
-
- Rect viewport(1920, 1200);
- bool snapped = SnapTransform(&result, transform, viewport);
-
- EXPECT_TRUE(snapped) << "Viewport should snap for this rotation.";
-}
-
-TEST(TransformUtilTest, SnapRotationDistantViewport) {
- const int kOffset = 5000;
- Transform result(Transform::kSkipInitialization);
- Transform transform;
-
- transform.RotateAboutZAxis(89.99);
-
- Rect viewport(kOffset, kOffset, 1920, 1200);
- bool snapped = SnapTransform(&result, transform, viewport);
-
- EXPECT_FALSE(snapped) << "Distant viewport shouldn't snap by more than 1px.";
-}
-
-TEST(TransformUtilTest, NoSnapRotation) {
- Transform result(Transform::kSkipInitialization);
- Transform transform;
- const int kOffset = 5000;
-
- transform.RotateAboutZAxis(89.9);
-
- Rect viewport(kOffset, kOffset, 1920, 1200);
- bool snapped = SnapTransform(&result, transform, viewport);
-
- EXPECT_FALSE(snapped) << "Viewport should not snap for this rotation.";
-}
-
-// Translations should always be snappable, the most we would move is 0.5
-// pixels towards either direction to the nearest value in each component.
-TEST(TransformUtilTest, SnapTranslation) {
- Transform result(Transform::kSkipInitialization);
- Transform transform;
-
- transform.Translate3d(SkDoubleToScalar(1.01), SkDoubleToScalar(1.99),
- SkDoubleToScalar(3.0));
-
- Rect viewport(1920, 1200);
- bool snapped = SnapTransform(&result, transform, viewport);
-
- EXPECT_TRUE(snapped) << "Viewport should snap for this translation.";
-}
-
-TEST(TransformUtilTest, SnapTranslationDistantViewport) {
- Transform result(Transform::kSkipInitialization);
- Transform transform;
- const int kOffset = 5000;
-
- transform.Translate3d(SkDoubleToScalar(1.01), SkDoubleToScalar(1.99),
- SkDoubleToScalar(3.0));
-
- Rect viewport(kOffset, kOffset, 1920, 1200);
- bool snapped = SnapTransform(&result, transform, viewport);
-
- EXPECT_TRUE(snapped)
- << "Distant viewport should still snap by less than 1px.";
-}
-
-TEST(TransformUtilTest, SnapScale) {
- Transform result(Transform::kSkipInitialization);
- Transform transform;
-
- transform.Scale3d(SkDoubleToScalar(5.0), SkDoubleToScalar(2.00001),
- SkDoubleToScalar(1.0));
- Rect viewport(1920, 1200);
- bool snapped = SnapTransform(&result, transform, viewport);
-
- EXPECT_TRUE(snapped) << "Viewport should snap for this scaling.";
-}
-
-TEST(TransformUtilTest, NoSnapScale) {
- Transform result(Transform::kSkipInitialization);
- Transform transform;
-
- transform.Scale3d(SkDoubleToScalar(5.0), SkDoubleToScalar(2.1),
- SkDoubleToScalar(1.0));
- Rect viewport(1920, 1200);
- bool snapped = SnapTransform(&result, transform, viewport);
-
- EXPECT_FALSE(snapped) << "Viewport shouldn't snap for this scaling.";
-}
-
-TEST(TransformUtilTest, SnapCompositeTransform) {
- Transform result(Transform::kSkipInitialization);
- Transform transform;
-
- transform.Translate3d(SkDoubleToScalar(30.5), SkDoubleToScalar(20.0),
- SkDoubleToScalar(10.1));
- transform.RotateAboutZAxis(89.99);
- transform.Scale3d(SkDoubleToScalar(1.0), SkDoubleToScalar(3.00001),
- SkDoubleToScalar(2.0));
-
- Rect viewport(1920, 1200);
- bool snapped = SnapTransform(&result, transform, viewport);
- ASSERT_TRUE(snapped) << "Viewport should snap all components.";
-
- Point3F point;
-
- point = Point3F(PointF(viewport.origin()));
- result.TransformPoint(&point);
- EXPECT_EQ(Point3F(31.f, 20.f, 10.f), point) << "Transformed origin";
-
- point = Point3F(PointF(viewport.top_right()));
- result.TransformPoint(&point);
- EXPECT_EQ(Point3F(31.f, 1940.f, 10.f), point) << "Transformed top-right";
-
- point = Point3F(PointF(viewport.bottom_left()));
- result.TransformPoint(&point);
- EXPECT_EQ(Point3F(-3569.f, 20.f, 10.f), point) << "Transformed bottom-left";
-
- point = Point3F(PointF(viewport.bottom_right()));
- result.TransformPoint(&point);
- EXPECT_EQ(Point3F(-3569.f, 1940.f, 10.f), point)
- << "Transformed bottom-right";
-}
-
-TEST(TransformUtilTest, NoSnapSkewedCompositeTransform) {
- Transform result(Transform::kSkipInitialization);
- Transform transform;
-
- transform.RotateAboutZAxis(89.99);
- transform.Scale3d(SkDoubleToScalar(1.0), SkDoubleToScalar(3.00001),
- SkDoubleToScalar(2.0));
- transform.Translate3d(SkDoubleToScalar(30.5), SkDoubleToScalar(20.0),
- SkDoubleToScalar(10.1));
- transform.Skew(20.0, 0.0);
- Rect viewport(1920, 1200);
- bool snapped = SnapTransform(&result, transform, viewport);
- EXPECT_FALSE(snapped) << "Skewed viewport should not snap.";
-}
-
TEST(TransformUtilTest, TransformAboutPivot) {
Transform transform;
transform.Scale(3, 4);
- transform = TransformAboutPivot(Point(7, 8), transform);
+ transform = TransformAboutPivot(PointF(7, 8), transform);
- Point point;
-
- point = Point(0, 0);
- transform.TransformPoint(&point);
+ Point point = transform.MapPoint(Point(0, 0));
EXPECT_EQ(Point(-14, -24).ToString(), point.ToString());
- point = Point(1, 1);
- transform.TransformPoint(&point);
+ point = transform.MapPoint(Point(1, 1));
EXPECT_EQ(Point(-11, -20).ToString(), point.ToString());
}
@@ -212,111 +70,21 @@
EXPECT_FALSE(std::isnan(result.quaternion.w()));
}
-double ComputeDecompRecompError(const Transform& transform) {
- DecomposedTransform decomp;
- DecomposeTransform(&decomp, transform);
- Transform composed = ComposeTransform(decomp);
-
- float expected[16];
- float actual[16];
- transform.matrix().asRowMajorf(expected);
- composed.matrix().asRowMajorf(actual);
- double sse = 0;
- for (int i = 0; i < 16; i++) {
- double diff = expected[i] - actual[i];
- sse += diff * diff;
- }
- return sse;
-}
-
-TEST(TransformUtilTest, RoundTripTest) {
- // rotateZ(90deg)
- EXPECT_APPROX_EQ(0, ComputeDecompRecompError(Transform(0, 1, -1, 0, 0, 0)));
-
- // rotateZ(180deg)
- // Edge case where w = 0.
- EXPECT_APPROX_EQ(0, ComputeDecompRecompError(Transform(-1, 0, 0, -1, 0, 0)));
-
- // rotateX(90deg) rotateY(90deg) rotateZ(90deg)
- // [1 0 0][ 0 0 1][0 -1 0] [0 0 1][0 -1 0] [0 0 1]
- // [0 0 -1][ 0 1 0][1 0 0] = [1 0 0][1 0 0] = [0 -1 0]
- // [0 1 0][-1 0 0][0 0 1] [0 1 0][0 0 1] [1 0 0]
- // This test case leads to Gimbal lock when using Euler angles.
- EXPECT_APPROX_EQ(0, ComputeDecompRecompError(Transform(
- 0, 0, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1)));
-
- // Quaternion matrices with 0 off-diagonal elements, and negative trace.
- // Stress tests handling of degenerate cases in computing quaternions.
- // Validates fix for https://crbug.com/647554.
- EXPECT_APPROX_EQ(0, ComputeDecompRecompError(Transform(1, 1, 1, 0, 0, 0)));
- EXPECT_APPROX_EQ(0, ComputeDecompRecompError(Transform(
- -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)));
- EXPECT_APPROX_EQ(0, ComputeDecompRecompError(Transform(
- 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)));
- EXPECT_APPROX_EQ(0, ComputeDecompRecompError(Transform(
- 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1)));
-}
-
-TEST(TransformUtilTest, Transform2D) {
- // The spec covering interpolation of 2D matrix transforms calls for inverting
- // one of the axis in the case of a negative determinant. This differs from
- // the general 3D spec, which calls for flipping all of the scales when the
- // determinant is negative. Flipping all scales not only introduces rotation
- // in the case of a trivial scale inversion, but causes transformed objects
- // to needlessly shrink and grow as they transform through scale = 0 along
- // multiple axes. 2D transformation matrices should follow the 2D spec
- // regarding matrix decomposition.
- DecomposedTransform decompFlipX;
- DecomposeTransform(&decompFlipX, Transform(-1, 0, 0, 1, 0, 0));
- EXPECT_APPROX_EQ(-1, decompFlipX.scale[0]);
- EXPECT_APPROX_EQ(1, decompFlipX.scale[1]);
- EXPECT_APPROX_EQ(1, decompFlipX.scale[2]);
- EXPECT_APPROX_EQ(0, decompFlipX.quaternion.z());
- EXPECT_APPROX_EQ(1, decompFlipX.quaternion.w());
-
- DecomposedTransform decompFlipY;
- DecomposeTransform(&decompFlipY, Transform(1, 0, 0, -1, 0, 0));
- EXPECT_APPROX_EQ(1, decompFlipY.scale[0]);
- EXPECT_APPROX_EQ(-1, decompFlipY.scale[1]);
- EXPECT_APPROX_EQ(1, decompFlipY.scale[2]);
- EXPECT_APPROX_EQ(0, decompFlipY.quaternion.z());
- EXPECT_APPROX_EQ(1, decompFlipY.quaternion.w());
-
- DecomposedTransform decompR180;
- DecomposeTransform(&decompR180, Transform(-1, 0, 0, -1, 0, 0));
- EXPECT_APPROX_EQ(1, decompR180.scale[0]);
- EXPECT_APPROX_EQ(1, decompR180.scale[1]);
- EXPECT_APPROX_EQ(1, decompR180.scale[2]);
- EXPECT_APPROX_EQ(1, decompR180.quaternion.z());
- EXPECT_APPROX_EQ(0, decompR180.quaternion.w());
-
- DecomposedTransform decompR90;
- DecomposeTransform(&decompR180, Transform(0, -1, 1, 0, 0, 0));
- EXPECT_APPROX_EQ(1, decompR180.scale[0]);
- EXPECT_APPROX_EQ(1, decompR180.scale[1]);
- EXPECT_APPROX_EQ(1, decompR180.scale[2]);
- EXPECT_APPROX_EQ(1 / sqrt(2), decompR180.quaternion.z());
- EXPECT_APPROX_EQ(1 / sqrt(2), decompR180.quaternion.w());
-
- DecomposedTransform decompR90Translate;
- DecomposeTransform(&decompR90Translate, Transform(0, -1, 1, 0, -1, 1));
- EXPECT_APPROX_EQ(1, decompR90Translate.scale[0]);
- EXPECT_APPROX_EQ(1, decompR90Translate.scale[1]);
- EXPECT_APPROX_EQ(1, decompR90Translate.scale[2]);
- EXPECT_APPROX_EQ(-1, decompR90Translate.translate[0]);
- EXPECT_APPROX_EQ(1, decompR90Translate.translate[1]);
- EXPECT_APPROX_EQ(0, decompR90Translate.translate[2]);
- EXPECT_APPROX_EQ(1 / sqrt(2), decompR90Translate.quaternion.z());
- EXPECT_APPROX_EQ(1 / sqrt(2), decompR90Translate.quaternion.w());
-
- DecomposedTransform decompSkewRotate;
- DecomposeTransform(&decompR90Translate, Transform(1, 1, 1, 0, 0, 0));
- EXPECT_APPROX_EQ(sqrt(2), decompR90Translate.scale[0]);
- EXPECT_APPROX_EQ(-1 / sqrt(2), decompR90Translate.scale[1]);
- EXPECT_APPROX_EQ(1, decompR90Translate.scale[2]);
- EXPECT_APPROX_EQ(-1, decompR90Translate.skew[0]);
- EXPECT_APPROX_EQ(sin(base::kPiDouble / 8), decompR90Translate.quaternion.z());
- EXPECT_APPROX_EQ(cos(base::kPiDouble / 8), decompR90Translate.quaternion.w());
+TEST(TransformUtilTest, AccumulateDecomposedTransforms) {
+ DecomposedTransform a{{2.5, -3.25, 4.75},
+ {4.5, -5.25, 6.75},
+ {1.25, -2.5, 3.75},
+ {5, -4, 3, -2},
+ {-5, 6, -7, 8}};
+ DecomposedTransform b{
+ {-2, 3, 4}, {-4, 5, 6}, {-1, 2, 3}, {6, 7, -8, -9}, {5, 4, -3, -2}};
+ DecomposedTransform expected{{0.5, -0.25, 8.75},
+ {-0.5, -1.25, 11.75},
+ {0.25, -0.5, 6.75},
+ {11, 3, -5, -12},
+ {+60, -30, -60, -36}};
+ EXPECT_DECOMPOSED_TRANSFORM_EQ(expected,
+ AccumulateDecomposedTransforms(a, b));
}
TEST(TransformUtilTest, TransformBetweenRects) {
@@ -325,16 +93,14 @@
// Applies |transform| to calculate the target rectangle from |src_rect|.
// Notes that |transform| is in |src_rect|'s local coordinates.
- RectF dst_in_src_coordinates = RectF(src_rect.size());
- transform.TransformRect(&dst_in_src_coordinates);
- RectF dst_in_parent_coordinates = dst_in_src_coordinates;
+ RectF dst_in_parent_coordinates = transform.MapRect(RectF(src_rect.size()));
dst_in_parent_coordinates.Offset(src_rect.OffsetFromOrigin());
// Verifies that the target rectangle is expected.
EXPECT_EQ(dst_rect, dst_in_parent_coordinates);
};
- std::vector<const std::pair<const RectF, const RectF>> test_cases{
+ std::vector<std::pair<const RectF, const RectF>> test_cases{
{RectF(0.f, 0.f, 2.f, 3.f), RectF(3.f, 5.f, 4.f, 9.f)},
{RectF(10.f, 7.f, 2.f, 6.f), RectF(4.f, 2.f, 1.f, 12.f)},
{RectF(0.f, 0.f, 3.f, 5.f), RectF(0.f, 0.f, 6.f, 2.5f)}};
@@ -348,5 +114,153 @@
verify(RectF(0.f, 0.f, 3.f, 5.f), RectF());
}
+TEST(TransformUtilTest, OrthoProjectionTransform) {
+ auto verify = [](float left, float right, float bottom, float top) {
+ AxisTransform2d t = OrthoProjectionTransform(left, right, bottom, top);
+ if (right == left || top == bottom) {
+ EXPECT_EQ(AxisTransform2d(), t);
+ } else {
+ EXPECT_EQ(PointF(-1, -1), t.MapPoint(PointF(left, bottom)));
+ EXPECT_EQ(PointF(1, 1), t.MapPoint(PointF(right, top)));
+ }
+ };
+
+ verify(0, 0, 0, 0);
+ verify(10, 20, 10, 30);
+ verify(10, 30, 20, 30);
+ verify(0, 0, 10, 20);
+ verify(-100, 400, 200, -200);
+ verify(-1.5, 4.25, 2.75, -3.75);
+}
+
+TEST(TransformUtilTest, WindowTransform) {
+ auto verify = [](int x, int y, int width, int height) {
+ AxisTransform2d t = WindowTransform(x, y, width, height);
+ EXPECT_EQ(PointF(x, y), t.MapPoint(PointF(-1, -1)));
+ EXPECT_EQ(PointF(x + width, y + height), t.MapPoint(PointF(1, 1)));
+ };
+
+ verify(0, 0, 0, 0);
+ verify(10, 20, 0, 30);
+ verify(10, 30, 20, 0);
+ verify(0, 0, 10, 20);
+ verify(-100, -400, 200, 300);
+}
+
+TEST(TransformUtilTest, Transform2dScaleComponents) {
+ // Values to test quiet NaN, infinity, and a denormal float if they're
+ // present; zero otherwise (since for the case this is used for, it
+ // should produce the same result).
+ const float quiet_NaN_or_zero = std::numeric_limits<float>::has_quiet_NaN
+ ? std::numeric_limits<float>::quiet_NaN()
+ : 0;
+ const float infinity_or_zero = std::numeric_limits<float>::has_infinity
+ ? std::numeric_limits<float>::infinity()
+ : 0;
+ const float denorm_min_or_zero =
+ (std::numeric_limits<float>::has_denorm == std::denorm_present)
+ ? std::numeric_limits<float>::denorm_min()
+ : 0;
+
+ const struct {
+ Transform transform;
+ absl::optional<Vector2dF> expected_scale;
+ } tests[] = {
+ // clang-format off
+ // A matrix with only scale and translation.
+ {Transform::RowMajor(3, 0, 0, -23,
+ 0, 7, 0, 31,
+ 0, 0, 11, 47,
+ 0, 0, 0, 1),
+ Vector2dF(3, 7)},
+ // Matrices like the first, but also with various
+ // perspective-altering components.
+ {Transform::RowMajor(3, 0, 0, -23,
+ 0, 7, 0, 31,
+ 0, 0, 11, 47,
+ 0, 0, -0.5, 1),
+ Vector2dF(3, 7)},
+ {Transform::RowMajor(3, 0, 0, -23,
+ 0, 7, 0, 31,
+ 0, 0, 11, 47,
+ 0.2f, 0, -0.5f, 1),
+ absl::nullopt},
+ {Transform::RowMajor(3, 0, 0, -23,
+ 0, 7, 0, 31,
+ 0, 0, 11, 47,
+ 0.2f, -0.2f, -0.5f, 1),
+ absl::nullopt},
+ {Transform::RowMajor(3, 0, 0, -23,
+ 0, 7, 0, 31,
+ 0, 0, 11, 47,
+ 0.2f, -0.2f, -0.5f, 1),
+ absl::nullopt},
+ {Transform::RowMajor(3, 0, 0, -23,
+ 0, 7, 0, 31,
+ 0, 0, 11, 47,
+ 0, -0.2f, -0.5f, 1),
+ absl::nullopt},
+ {Transform::RowMajor(3, 0, 0, -23,
+ 0, 7, 0, 31,
+ 0, 0, 11, 47,
+ 0, 0, -0.5f, 0.25f),
+ Vector2dF(12, 28)},
+ // Matrices like the first, but with some types of rotation.
+ {Transform::RowMajor(0, 3, 0, -23,
+ 7, 0, 0, 31,
+ 0, 0, 11, 47,
+ 0, 0, 0, 1),
+ Vector2dF(7, 3)},
+ {Transform::RowMajor(3, 8, 0, -23,
+ 4, 6, 0, 31,
+ 0, 0, 11, 47,
+ 0, 0, 0, 1),
+ Vector2dF(5, 10)},
+ // Combination of rotation and perspective
+ {Transform::RowMajor(3, 8, 0, -23,
+ 4, 6, 0, 31,
+ 0, 0, 11, 47,
+ 0, 0, 0, 0.25f),
+ Vector2dF(20, 40)},
+ // Error handling cases for final perspective component.
+ {Transform::RowMajor(3, 0, 0, -23,
+ 0, 7, 0, 31,
+ 0, 0, 11, 47,
+ 0, 0, 0, 0),
+ absl::nullopt},
+ {Transform::RowMajor(3, 0, 0, -23,
+ 0, 7, 0, 31,
+ 0, 0, 11, 47,
+ 0, 0, 0, quiet_NaN_or_zero),
+ absl::nullopt},
+ {Transform::RowMajor(3, 0, 0, -23,
+ 0, 7, 0, 31,
+ 0, 0, 11, 47,
+ 0, 0, 0, infinity_or_zero),
+ absl::nullopt},
+ {Transform::RowMajor(3, 0, 0, -23,
+ 0, 7, 0, 31,
+ 0, 0, 11, 47,
+ 0, 0, 0, denorm_min_or_zero),
+ absl::nullopt},
+ // clang-format on
+ };
+
+ const float fallback = 1.409718f; // randomly generated in [1,2)
+
+ for (const auto& test : tests) {
+ absl::optional<Vector2dF> try_result =
+ TryComputeTransform2dScaleComponents(test.transform);
+ EXPECT_EQ(try_result, test.expected_scale);
+ Vector2dF result =
+ ComputeTransform2dScaleComponents(test.transform, fallback);
+ if (test.expected_scale) {
+ EXPECT_EQ(result, *test.expected_scale);
+ } else {
+ EXPECT_EQ(result, Vector2dF(fallback, fallback));
+ }
+ }
+}
+
} // namespace
} // namespace gfx
diff --git a/ui/gfx/geometry/triangle_f.cc b/ui/gfx/geometry/triangle_f.cc
new file mode 100644
index 0000000..84c0436
--- /dev/null
+++ b/ui/gfx/geometry/triangle_f.cc
@@ -0,0 +1,42 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/triangle_f.h"
+
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace gfx {
+
+bool PointIsInTriangle(const PointF& point,
+ const PointF& r1,
+ const PointF& r2,
+ const PointF& r3) {
+ // Compute the barycentric coordinates (u, v, w) of |point| relative to the
+ // triangle (r1, r2, r3) by the solving the system of equations:
+ // 1) point = u * r1 + v * r2 + w * r3
+ // 2) u + v + w = 1
+ // This algorithm comes from Christer Ericson's Real-Time Collision Detection.
+
+ Vector2dF r31 = r1 - r3;
+ Vector2dF r32 = r2 - r3;
+ Vector2dF r3p = point - r3;
+
+ // Promote to doubles so all the math below is done with doubles, because
+ // otherwise it gets incorrect results on arm64.
+ double r31x = r31.x();
+ double r31y = r31.y();
+ double r32x = r32.x();
+ double r32y = r32.y();
+
+ double denom = r32y * r31x - r32x * r31y;
+ double u = (r32y * r3p.x() - r32x * r3p.y()) / denom;
+ double v = (r31x * r3p.y() - r31y * r3p.x()) / denom;
+ double w = 1.0 - u - v;
+
+ // Use the barycentric coordinates to test if |point| is inside the
+ // triangle (r1, r2, r2).
+ return (u >= 0) && (v >= 0) && (w >= 0);
+}
+
+} // namespace gfx
\ No newline at end of file
diff --git a/ui/gfx/geometry/triangle_f.h b/ui/gfx/geometry/triangle_f.h
new file mode 100644
index 0000000..761e2f2
--- /dev/null
+++ b/ui/gfx/geometry/triangle_f.h
@@ -0,0 +1,20 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_GEOMETRY_TRIANGLE_F_H_
+#define UI_GFX_GEOMETRY_TRIANGLE_F_H_
+
+#include "ui/gfx/geometry/geometry_export.h"
+#include "ui/gfx/geometry/point_f.h"
+
+namespace gfx {
+
+GEOMETRY_EXPORT bool PointIsInTriangle(const PointF& point,
+ const PointF& r1,
+ const PointF& r2,
+ const PointF& r3);
+
+}
+
+#endif // UI_GFX_GEOMETRY_TRIANGLE_F_H_
\ No newline at end of file
diff --git a/ui/gfx/geometry/triangle_unittest.cc b/ui/gfx/geometry/triangle_unittest.cc
new file mode 100644
index 0000000..4272717
--- /dev/null
+++ b/ui/gfx/geometry/triangle_unittest.cc
@@ -0,0 +1,43 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <stddef.h>
+
+#include "base/cxx17_backports.h"
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/triangle_f.h"
+
+namespace gfx {
+
+namespace {
+constexpr PointF kPointA(1, 1);
+constexpr PointF kPointB(10, 1);
+constexpr PointF kPointC(1, 10);
+} // namespace
+
+TEST(TriangleTest, PointIsInTriangleInside) {
+ PointF p(2, 2);
+
+ EXPECT_TRUE(PointIsInTriangle(p, kPointA, kPointB, kPointC));
+}
+
+TEST(TriangleTest, PointIsInTriangleOutside) {
+ PointF o(0, 0);
+
+ EXPECT_FALSE(PointIsInTriangle(o, kPointA, kPointB, kPointC));
+}
+
+TEST(TriangleTest, PointIsInTriangleEdge) {
+ PointF e(1, 3);
+
+ EXPECT_TRUE(PointIsInTriangle(e, kPointA, kPointB, kPointC));
+}
+
+TEST(TriangleTest, PointIsInTriangleVertex) {
+ EXPECT_TRUE(PointIsInTriangle(kPointA, kPointA, kPointB, kPointC));
+}
+
+} // namespace gfx
\ No newline at end of file
diff --git a/ui/gfx/geometry/vector2d.cc b/ui/gfx/geometry/vector2d.cc
index 0ce3b20..81fb52b 100644
--- a/ui/gfx/geometry/vector2d.cc
+++ b/ui/gfx/geometry/vector2d.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -25,6 +25,10 @@
y_ = base::ClampSub(y_, other.y_);
}
+Vector2d operator-(const Vector2d& v) {
+ return Vector2d(-base::MakeClampedNum(v.x()), -base::MakeClampedNum(v.y()));
+}
+
int64_t Vector2d::LengthSquared() const {
return static_cast<int64_t>(x_) * x_ + static_cast<int64_t>(y_) * y_;
}
diff --git a/ui/gfx/geometry/vector2d.h b/ui/gfx/geometry/vector2d.h
index 86ad260..4524f92 100644
--- a/ui/gfx/geometry/vector2d.h
+++ b/ui/gfx/geometry/vector2d.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,28 +10,25 @@
#ifndef UI_GFX_GEOMETRY_VECTOR2D_H_
#define UI_GFX_GEOMETRY_VECTOR2D_H_
+#include <stdint.h>
+
#include <iosfwd>
#include <string>
-#include "base/basictypes.h"
+#include "ui/gfx/geometry/geometry_export.h"
#include "ui/gfx/geometry/vector2d_f.h"
namespace gfx {
-class Vector2d {
+class GEOMETRY_EXPORT Vector2d {
public:
- Vector2d() : x_(0), y_(0) {}
- Vector2d(int x, int y) : x_(x), y_(y) {}
+ constexpr Vector2d() : x_(0), y_(0) {}
+ constexpr Vector2d(int x, int y) : x_(x), y_(y) {}
- void SetVector(int x, int y) {
- x_ = x;
- y_ = y;
- }
-
- int x() const { return x_; }
+ constexpr int x() const { return x_; }
void set_x(int x) { x_ = x; }
- int y() const { return y_; }
+ constexpr int y() const { return y_; }
void set_y(int y) { y_ = y; }
// True if both components of the vector are 0.
@@ -42,30 +39,38 @@
// Subtract the components of the |other| vector from the current vector.
void Subtract(const Vector2d& other);
+ constexpr bool operator==(const Vector2d& other) const {
+ return x_ == other.x_ && y_ == other.y_;
+ }
void operator+=(const Vector2d& other) { Add(other); }
void operator-=(const Vector2d& other) { Subtract(other); }
void SetToMin(const Vector2d& other) {
- x_ = x_ <= other.x_ ? x_ : other.x_;
- y_ = y_ <= other.y_ ? y_ : other.y_;
+ x_ = std::min(x_, other.x_);
+ y_ = std::min(y_, other.y_);
}
void SetToMax(const Vector2d& other) {
- x_ = x_ >= other.x_ ? x_ : other.x_;
- y_ = y_ >= other.y_ ? y_ : other.y_;
+ x_ = std::max(x_, other.x_);
+ y_ = std::max(y_, other.y_);
}
// Gives the square of the diagonal length of the vector. Since this is
// cheaper to compute than Length(), it is useful when you want to compare
// relative lengths of different vectors without needing the actual lengths.
- int64 LengthSquared() const;
+ int64_t LengthSquared() const;
// Gives the diagonal length of the vector.
float Length() const;
+ void Transpose() {
+ using std::swap;
+ swap(x_, y_);
+ }
+
std::string ToString() const;
operator Vector2dF() const {
- return Vector2dF(static_cast<float>(x_), static_cast<float>(y_));
+ return Vector2dF(static_cast<float>(x()), static_cast<float>(y()));
}
private:
@@ -73,13 +78,7 @@
int y_;
};
-inline bool operator==(const Vector2d& lhs, const Vector2d& rhs) {
- return lhs.x() == rhs.x() && lhs.y() == rhs.y();
-}
-
-inline Vector2d operator-(const Vector2d& v) {
- return Vector2d(-v.x(), -v.y());
-}
+GEOMETRY_EXPORT Vector2d operator-(const Vector2d&);
inline Vector2d operator+(const Vector2d& lhs, const Vector2d& rhs) {
Vector2d result = lhs;
@@ -89,10 +88,19 @@
inline Vector2d operator-(const Vector2d& lhs, const Vector2d& rhs) {
Vector2d result = lhs;
- result.Add(-rhs);
+ result.Subtract(rhs);
return result;
}
+inline Vector2d TransposeVector2d(const Vector2d& v) {
+ return Vector2d(v.y(), v.x());
+}
+
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const Vector2d& vector, ::std::ostream* os);
+
} // namespace gfx
-#endif // UI_GFX_GEOMETRY_VECTOR2D_H_
+#endif // UI_GFX_GEOMETRY_VECTOR2D_H_
diff --git a/ui/gfx/geometry/vector2d_conversions.cc b/ui/gfx/geometry/vector2d_conversions.cc
index c33199b..cbed01b 100644
--- a/ui/gfx/geometry/vector2d_conversions.cc
+++ b/ui/gfx/geometry/vector2d_conversions.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/vector2d_conversions.h b/ui/gfx/geometry/vector2d_conversions.h
index 055ebd0..2769731 100644
--- a/ui/gfx/geometry/vector2d_conversions.h
+++ b/ui/gfx/geometry/vector2d_conversions.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/geometry/vector2d_f.cc b/ui/gfx/geometry/vector2d_f.cc
index ccb15ae..1578cab 100644
--- a/ui/gfx/geometry/vector2d_f.cc
+++ b/ui/gfx/geometry/vector2d_f.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,13 +7,25 @@
#include <cmath>
#include "base/strings/stringprintf.h"
+#if !defined(STARBOARD)
+#include "base/trace_event/typed_macros.h"
+#endif // !defined(STARBOARD)
+#include "build/build_config.h"
namespace gfx {
std::string Vector2dF::ToString() const {
- return base::StringPrintf("[%f %f]", x_, y_);
+ return base::StringPrintf("[%g %g]", x_, y_);
}
+#if !defined(STARBOARD)
+void Vector2dF::WriteIntoTrace(perfetto::TracedValue ctx) const {
+ perfetto::TracedDictionary dict = std::move(ctx).WriteDictionary();
+ dict.Add("x", x_);
+ dict.Add("y", y_);
+}
+#endif // !defined(STARBOARD)
+
bool Vector2dF::IsZero() const {
return x_ == 0 && y_ == 0;
}
@@ -33,7 +45,7 @@
}
float Vector2dF::Length() const {
- return static_cast<float>(std::sqrt(LengthSquared()));
+ return hypotf(x_, y_);
}
void Vector2dF::Scale(float x_scale, float y_scale) {
@@ -41,6 +53,11 @@
y_ *= y_scale;
}
+void Vector2dF::InvScale(float inv_x_scale, float inv_y_scale) {
+ x_ /= inv_x_scale;
+ y_ /= inv_y_scale;
+}
+
double CrossProduct(const Vector2dF& lhs, const Vector2dF& rhs) {
return static_cast<double>(lhs.x()) * rhs.y() -
static_cast<double>(lhs.y()) * rhs.x();
@@ -57,4 +74,15 @@
return scaled_v;
}
+float Vector2dF::SlopeAngleRadians() const {
+#if BUILDFLAG(IS_MAC)
+ // atan2f(...) returns less accurate results on Mac.
+ // 3.1415925 vs. 3.14159274 for atan2f(0, -50) as an example.
+ return static_cast<float>(
+ atan2(static_cast<double>(y_), static_cast<double>(x_)));
+#else
+ return atan2f(y_, x_);
+#endif
+}
+
} // namespace gfx
diff --git a/ui/gfx/geometry/vector2d_f.h b/ui/gfx/geometry/vector2d_f.h
index f97ef00..73c967f 100644
--- a/ui/gfx/geometry/vector2d_f.h
+++ b/ui/gfx/geometry/vector2d_f.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -13,24 +13,22 @@
#include <iosfwd>
#include <string>
-#include "base/logging.h"
+#include "ui/gfx/geometry/geometry_export.h"
+namespace perfetto {
+class TracedValue;
+}
namespace gfx {
-class Vector2dF {
+class GEOMETRY_EXPORT Vector2dF {
public:
- Vector2dF() : x_(0), y_(0) {}
- Vector2dF(float x, float y) : x_(x), y_(y) {}
+ constexpr Vector2dF() : x_(0), y_(0) {}
+ constexpr Vector2dF(float x, float y) : x_(x), y_(y) {}
- void SetVector(float x, float y) {
- x_ = x;
- y_ = y;
- }
-
- float x() const { return x_; }
+ constexpr float x() const { return x_; }
void set_x(float x) { x_ = x; }
- float y() const { return y_; }
+ constexpr float y() const { return y_; }
void set_y(float y) { y_ = y; }
// True if both components of the vector are 0.
@@ -44,54 +42,66 @@
void operator+=(const Vector2dF& other) { Add(other); }
void operator-=(const Vector2dF& other) { Subtract(other); }
- float operator[](int i) const {
- DCHECK_LE(0, i);
- DCHECK_GE(1, i);
- return i == 0 ? x_ : y_;
- }
- float& operator[](int i) {
- DCHECK_LE(0, i);
- DCHECK_GE(1, i);
- return i == 0 ? x_ : y_;
- }
-
void SetToMin(const Vector2dF& other) {
- x_ = x_ <= other.x_ ? x_ : other.x_;
- y_ = y_ <= other.y_ ? y_ : other.y_;
+ x_ = std::min(x_, other.x_);
+ y_ = std::min(y_, other.y_);
}
void SetToMax(const Vector2dF& other) {
- x_ = x_ >= other.x_ ? x_ : other.x_;
- y_ = y_ >= other.y_ ? y_ : other.y_;
+ x_ = std::max(x_, other.x_);
+ y_ = std::max(y_, other.y_);
}
- // Gives the square of the diagonal length of the vector.
+ // Gives the square of the diagonal length, i.e. the square of magnitude, of
+ // the vector.
double LengthSquared() const;
- // Gives the diagonal length of the vector.
+
+ // Gives the diagonal length (i.e. the magnitude) of the vector.
float Length() const;
+ float AspectRatio() const { return x_ / y_; }
+
+ // Gives the slope angle in radians of the vector from the positive x axis,
+ // in the range of (-pi, pi]. The sign of the result is the same as the sign
+ // of y(), except that the result is pi for Vector2dF(negative-x, zero-y).
+ float SlopeAngleRadians() const;
+
// Scale the x and y components of the vector by |scale|.
void Scale(float scale) { Scale(scale, scale); }
// Scale the x and y components of the vector by |x_scale| and |y_scale|
// respectively.
void Scale(float x_scale, float y_scale);
+ // Divides all components of the vector by |scale|.
+ void InvScale(float inv_scale) { InvScale(inv_scale, inv_scale); }
+ // Divides each component of the vector by the given scale factors.
+ void InvScale(float inv_x_scale, float inv_y_scale);
+
+ void Transpose() {
+ using std::swap;
+ swap(x_, y_);
+ }
+
std::string ToString() const;
+#if !defined(STARBOARD)
+ void WriteIntoTrace(perfetto::TracedValue) const;
+#endif // !defined(STARBOARD)
+
private:
float x_;
float y_;
};
-inline bool operator==(const Vector2dF& lhs, const Vector2dF& rhs) {
+inline constexpr bool operator==(const Vector2dF& lhs, const Vector2dF& rhs) {
return lhs.x() == rhs.x() && lhs.y() == rhs.y();
}
-inline bool operator!=(const Vector2dF& lhs, const Vector2dF& rhs) {
+inline constexpr bool operator!=(const Vector2dF& lhs, const Vector2dF& rhs) {
return !(lhs == rhs);
}
-inline Vector2dF operator-(const Vector2dF& v) {
+inline constexpr Vector2dF operator-(const Vector2dF& v) {
return Vector2dF(-v.x(), -v.y());
}
@@ -107,21 +117,32 @@
return result;
}
-// Return the cross product of two vectors.
-double CrossProduct(const Vector2dF& lhs, const Vector2dF& rhs);
+// Return the cross product of two vectors, i.e. the determinant.
+GEOMETRY_EXPORT double CrossProduct(const Vector2dF& lhs, const Vector2dF& rhs);
// Return the dot product of two vectors.
-double DotProduct(const Vector2dF& lhs, const Vector2dF& rhs);
+GEOMETRY_EXPORT double DotProduct(const Vector2dF& lhs, const Vector2dF& rhs);
// Return a vector that is |v| scaled by the given scale factors along each
// axis.
-Vector2dF ScaleVector2d(const Vector2dF& v, float x_scale, float y_scale);
+GEOMETRY_EXPORT Vector2dF ScaleVector2d(const Vector2dF& v,
+ float x_scale,
+ float y_scale);
// Return a vector that is |v| scaled by the given scale factor.
inline Vector2dF ScaleVector2d(const Vector2dF& v, float scale) {
return ScaleVector2d(v, scale, scale);
}
+inline Vector2dF TransposeVector2d(const Vector2dF& v) {
+ return Vector2dF(v.y(), v.x());
+}
+
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const Vector2dF& vector, ::std::ostream* os);
+
} // namespace gfx
-#endif // UI_GFX_GEOMETRY_VECTOR2D_F_H_
+#endif // UI_GFX_GEOMETRY_VECTOR2D_F_H_
diff --git a/ui/gfx/geometry/vector2d_f_unittest.cc b/ui/gfx/geometry/vector2d_f_unittest.cc
new file mode 100644
index 0000000..5f6902f
--- /dev/null
+++ b/ui/gfx/geometry/vector2d_f_unittest.cc
@@ -0,0 +1,154 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/geometry/vector2d_f.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/test/geometry_util.h"
+#include "ui/gfx/geometry/vector2d.h"
+
+namespace gfx {
+
+TEST(Vector2dTest, Vector2dToVector2dF) {
+ Vector2d i(3, 4);
+ Vector2dF f = i;
+ EXPECT_EQ(i, f);
+}
+
+TEST(Vector2dFTest, IsZero) {
+ EXPECT_TRUE(Vector2dF().IsZero());
+ EXPECT_TRUE(Vector2dF(0, 0).IsZero());
+ EXPECT_FALSE(Vector2dF(0.1f, 0).IsZero());
+ EXPECT_FALSE(Vector2dF(0, -0.1f).IsZero());
+ EXPECT_FALSE(Vector2dF(0.1f, -0.1f).IsZero());
+}
+
+TEST(Vector2dFTest, Add) {
+ Vector2dF f1(3.1f, 5.1f);
+ Vector2dF f2(4.3f, -1.3f);
+ EXPECT_VECTOR2DF_EQ(Vector2dF(3.1f, 5.1f), f1 + Vector2dF());
+ EXPECT_VECTOR2DF_EQ(Vector2dF(3.1f + 4.3f, 5.1f - 1.3f), f1 + f2);
+ EXPECT_VECTOR2DF_EQ(Vector2dF(3.1f - 4.3f, 5.1f + 1.3f), f1 - f2);
+}
+
+TEST(Vector2dFTest, Negative) {
+ EXPECT_VECTOR2DF_EQ(Vector2dF(), -Vector2dF());
+ EXPECT_VECTOR2DF_EQ(Vector2dF(-0.3f, -0.3f), -Vector2dF(0.3f, 0.3f));
+ EXPECT_VECTOR2DF_EQ(Vector2dF(0.3f, 0.3f), -Vector2dF(-0.3f, -0.3f));
+ EXPECT_VECTOR2DF_EQ(Vector2dF(-0.3f, 0.3f), -Vector2dF(0.3f, -0.3f));
+ EXPECT_VECTOR2DF_EQ(Vector2dF(0.3f, -0.3f), -Vector2dF(-0.3f, 0.3f));
+}
+
+TEST(Vector2dFTest, Scale) {
+ float double_values[][4] = {
+ {4.5f, 1.2f, 3.3f, 5.6f}, {4.5f, -1.2f, 3.3f, 5.6f},
+ {4.5f, 1.2f, 3.3f, -5.6f}, {4.5f, 1.2f, -3.3f, -5.6f},
+ {-4.5f, 1.2f, 3.3f, 5.6f}, {-4.5f, 1.2f, 0, 5.6f},
+ {-4.5f, 1.2f, 3.3f, 0}, {4.5f, 0, 3.3f, 5.6f},
+ {0, 1.2f, 3.3f, 5.6f}};
+
+ for (auto& values : double_values) {
+ Vector2dF v(values[0], values[1]);
+ v.Scale(values[2], values[3]);
+ EXPECT_EQ(v.x(), values[0] * values[2]);
+ EXPECT_EQ(v.y(), values[1] * values[3]);
+
+ Vector2dF v2 = ScaleVector2d(gfx::Vector2dF(values[0], values[1]),
+ values[2], values[3]);
+ EXPECT_EQ(values[0] * values[2], v2.x());
+ EXPECT_EQ(values[1] * values[3], v2.y());
+ }
+
+ float single_values[][3] = {
+ {4.5f, 1.2f, 3.3f}, {4.5f, -1.2f, 3.3f}, {4.5f, 1.2f, 3.3f},
+ {4.5f, 1.2f, -3.3f}, {-4.5f, 1.2f, 3.3f}, {-4.5f, 1.2f, 0},
+ {-4.5f, 1.2f, 3.3f}, {4.5f, 0, 3.3f}, {0, 1.2f, 3.3f}};
+
+ for (auto& values : single_values) {
+ Vector2dF v(values[0], values[1]);
+ v.Scale(values[2]);
+ EXPECT_EQ(v.x(), values[0] * values[2]);
+ EXPECT_EQ(v.y(), values[1] * values[2]);
+
+ Vector2dF v2 =
+ ScaleVector2d(gfx::Vector2dF(values[0], values[1]), values[2]);
+ EXPECT_EQ(values[0] * values[2], v2.x());
+ EXPECT_EQ(values[1] * values[2], v2.y());
+ }
+}
+
+TEST(Vector2dFTest, SetToMinMax) {
+ Vector2dF a;
+
+ a = Vector2dF(3.5f, 5.5f);
+ EXPECT_EQ(Vector2dF(3.5f, 5.5f), a);
+ a.SetToMax(Vector2dF(2.5f, 4.5f));
+ EXPECT_EQ(Vector2dF(3.5f, 5.5f), a);
+ a.SetToMax(Vector2dF(3.5f, 5.5f));
+ EXPECT_EQ(Vector2dF(3.5f, 5.5f), a);
+ a.SetToMax(Vector2dF(4.5f, 2.5f));
+ EXPECT_EQ(Vector2dF(4.5f, 5.5f), a);
+ a.SetToMax(Vector2dF(8.5f, 10.5f));
+ EXPECT_EQ(Vector2dF(8.5f, 10.5f), a);
+
+ a.SetToMin(Vector2dF(9.5f, 11.5f));
+ EXPECT_EQ(Vector2dF(8.5f, 10.5f), a);
+ a.SetToMin(Vector2dF(8.5f, 10.5f));
+ EXPECT_EQ(Vector2dF(8.5f, 10.5f), a);
+ a.SetToMin(Vector2dF(11.5f, 9.5f));
+ EXPECT_EQ(Vector2dF(8.5f, 9.5f), a);
+ a.SetToMin(Vector2dF(7.5f, 11.5f));
+ EXPECT_EQ(Vector2dF(7.5f, 9.5f), a);
+ a.SetToMin(Vector2dF(3.5f, 5.5f));
+ EXPECT_EQ(Vector2dF(3.5f, 5.5f), a);
+}
+
+TEST(Vector2dFTest, Length) {
+ constexpr float kFloatMax = std::numeric_limits<float>::max();
+ EXPECT_FLOAT_EQ(0.f, Vector2dF(0, 0).Length());
+ EXPECT_FLOAT_EQ(1.f, Vector2dF(1, 0).Length());
+ EXPECT_FLOAT_EQ(1.414214f, Vector2dF(1, 1).Length());
+ EXPECT_FLOAT_EQ(2.236068f, Vector2dF(-1, -2).Length());
+
+ // The Pythagorean triples 3-4-5 and 5-12-13.
+ EXPECT_FLOAT_EQ(5.f, Vector2dF(3.f, 4.f).Length());
+ EXPECT_FLOAT_EQ(13.f, Vector2dF(5.f, 12.f).Length());
+
+ // Very small numbers.
+ EXPECT_FLOAT_EQ(.7071068e-20f, Vector2dF(.5e-20f, .5e-20f).Length());
+
+ // Very large numbers.
+ EXPECT_FLOAT_EQ(.7071068e20f, Vector2dF(.5e20f, .5e20f).Length());
+ EXPECT_FLOAT_EQ(kFloatMax, Vector2dF(kFloatMax, 0).Length());
+ EXPECT_FLOAT_EQ(kFloatMax, Vector2dF(kFloatMax, kFloatMax).Length());
+}
+
+TEST(Vector2dFTest, SlopeAngleRadians) {
+ // The function is required to be very accurate, so we use a smaller
+ // tolerance than EXPECT_FLOAT_EQ().
+ constexpr float kTolerance = 1e-7f;
+ constexpr float kPi = 3.1415927f;
+ EXPECT_NEAR(0, Vector2dF(0, 0).SlopeAngleRadians(), kTolerance);
+ EXPECT_NEAR(0, Vector2dF(1, 0).SlopeAngleRadians(), kTolerance);
+ EXPECT_NEAR(kPi / 4, Vector2dF(1, 1).SlopeAngleRadians(), kTolerance);
+ EXPECT_NEAR(kPi / 2, Vector2dF(0, 1).SlopeAngleRadians(), kTolerance);
+ EXPECT_NEAR(kPi, Vector2dF(-50, 0).SlopeAngleRadians(), kTolerance);
+ EXPECT_NEAR(-kPi * 3 / 4, Vector2dF(-50, -50).SlopeAngleRadians(),
+ kTolerance);
+ EXPECT_NEAR(-kPi / 4, Vector2dF(1, -1).SlopeAngleRadians(), kTolerance);
+}
+
+TEST(Vector2dFTest, Transpose) {
+ gfx::Vector2dF v(-1.5f, 2.5f);
+ EXPECT_EQ(gfx::Vector2dF(2.5f, -1.5f), TransposeVector2d(v));
+ v.Transpose();
+ EXPECT_EQ(gfx::Vector2dF(2.5f, -1.5f), v);
+}
+
+TEST(Vector2dFTest, ToString) {
+ EXPECT_EQ("[1 2]", Vector2dF(1, 2).ToString());
+ EXPECT_EQ("[1.03125 2.5]", Vector2dF(1.03125, 2.5).ToString());
+}
+
+} // namespace gfx
diff --git a/ui/gfx/geometry/vector2d_unittest.cc b/ui/gfx/geometry/vector2d_unittest.cc
index f4e754b..c1ab815 100644
--- a/ui/gfx/geometry/vector2d_unittest.cc
+++ b/ui/gfx/geometry/vector2d_unittest.cc
@@ -1,169 +1,49 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include <stddef.h>
+#include "ui/gfx/geometry/vector2d.h"
+#include <stddef.h>
#include <cmath>
#include <limits>
-#include "base/cxx17_backports.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/vector2d.h"
-#include "ui/gfx/geometry/vector2d_f.h"
namespace gfx {
-TEST(Vector2dTest, ConversionToFloat) {
- Vector2d i(3, 4);
- Vector2dF f = i;
- EXPECT_EQ(i, f);
-}
-
TEST(Vector2dTest, IsZero) {
- Vector2d int_zero(0, 0);
- Vector2d int_nonzero(2, -2);
- Vector2dF float_zero(0, 0);
- Vector2dF float_nonzero(0.1f, -0.1f);
-
- EXPECT_TRUE(int_zero.IsZero());
- EXPECT_FALSE(int_nonzero.IsZero());
- EXPECT_TRUE(float_zero.IsZero());
- EXPECT_FALSE(float_nonzero.IsZero());
+ EXPECT_TRUE(Vector2d().IsZero());
+ EXPECT_TRUE(Vector2d(0, 0).IsZero());
+ EXPECT_FALSE(Vector2d(1, 0).IsZero());
+ EXPECT_FALSE(Vector2d(0, -2).IsZero());
+ EXPECT_FALSE(Vector2d(1, -2).IsZero());
}
TEST(Vector2dTest, Add) {
Vector2d i1(3, 5);
Vector2d i2(4, -1);
-
- const struct {
- Vector2d expected;
- Vector2d actual;
- } int_tests[] = {
- { Vector2d(3, 5), i1 + Vector2d() },
- { Vector2d(3 + 4, 5 - 1), i1 + i2 },
- { Vector2d(3 - 4, 5 + 1), i1 - i2 }
- };
-
- for (size_t i = 0; i < base::size(int_tests); ++i)
- EXPECT_EQ(int_tests[i].expected.ToString(),
- int_tests[i].actual.ToString());
-
- Vector2dF f1(3.1f, 5.1f);
- Vector2dF f2(4.3f, -1.3f);
-
- const struct {
- Vector2dF expected;
- Vector2dF actual;
- } float_tests[] = {
- { Vector2dF(3.1F, 5.1F), f1 + Vector2d() },
- { Vector2dF(3.1F, 5.1F), f1 + Vector2dF() },
- { Vector2dF(3.1f + 4.3f, 5.1f - 1.3f), f1 + f2 },
- { Vector2dF(3.1f - 4.3f, 5.1f + 1.3f), f1 - f2 }
- };
-
- for (size_t i = 0; i < base::size(float_tests); ++i)
- EXPECT_EQ(float_tests[i].expected.ToString(),
- float_tests[i].actual.ToString());
+ EXPECT_EQ(Vector2d(3, 5), i1 + Vector2d());
+ EXPECT_EQ(Vector2d(3 + 4, 5 - 1), i1 + i2);
+ EXPECT_EQ(Vector2d(3 - 4, 5 + 1), i1 - i2);
}
TEST(Vector2dTest, Negative) {
- const struct {
- Vector2d expected;
- Vector2d actual;
- } int_tests[] = {
- { Vector2d(0, 0), -Vector2d(0, 0) },
- { Vector2d(-3, -3), -Vector2d(3, 3) },
- { Vector2d(3, 3), -Vector2d(-3, -3) },
- { Vector2d(-3, 3), -Vector2d(3, -3) },
- { Vector2d(3, -3), -Vector2d(-3, 3) }
- };
-
- for (size_t i = 0; i < base::size(int_tests); ++i)
- EXPECT_EQ(int_tests[i].expected.ToString(),
- int_tests[i].actual.ToString());
-
- const struct {
- Vector2dF expected;
- Vector2dF actual;
- } float_tests[] = {
- { Vector2dF(0, 0), -Vector2d(0, 0) },
- { Vector2dF(-0.3f, -0.3f), -Vector2dF(0.3f, 0.3f) },
- { Vector2dF(0.3f, 0.3f), -Vector2dF(-0.3f, -0.3f) },
- { Vector2dF(-0.3f, 0.3f), -Vector2dF(0.3f, -0.3f) },
- { Vector2dF(0.3f, -0.3f), -Vector2dF(-0.3f, 0.3f) }
- };
-
- for (size_t i = 0; i < base::size(float_tests); ++i)
- EXPECT_EQ(float_tests[i].expected.ToString(),
- float_tests[i].actual.ToString());
-}
-
-TEST(Vector2dTest, Scale) {
- float double_values[][4] = {
- { 4.5f, 1.2f, 3.3f, 5.6f },
- { 4.5f, -1.2f, 3.3f, 5.6f },
- { 4.5f, 1.2f, 3.3f, -5.6f },
- { 4.5f, 1.2f, -3.3f, -5.6f },
- { -4.5f, 1.2f, 3.3f, 5.6f },
- { -4.5f, 1.2f, 0, 5.6f },
- { -4.5f, 1.2f, 3.3f, 0 },
- { 4.5f, 0, 3.3f, 5.6f },
- { 0, 1.2f, 3.3f, 5.6f }
- };
-
- for (size_t i = 0; i < base::size(double_values); ++i) {
- Vector2dF v(double_values[i][0], double_values[i][1]);
- v.Scale(double_values[i][2], double_values[i][3]);
- EXPECT_EQ(v.x(), double_values[i][0] * double_values[i][2]);
- EXPECT_EQ(v.y(), double_values[i][1] * double_values[i][3]);
-
- Vector2dF v2 = ScaleVector2d(
- gfx::Vector2dF(double_values[i][0], double_values[i][1]),
- double_values[i][2], double_values[i][3]);
- EXPECT_EQ(double_values[i][0] * double_values[i][2], v2.x());
- EXPECT_EQ(double_values[i][1] * double_values[i][3], v2.y());
- }
-
- float single_values[][3] = {
- { 4.5f, 1.2f, 3.3f },
- { 4.5f, -1.2f, 3.3f },
- { 4.5f, 1.2f, 3.3f },
- { 4.5f, 1.2f, -3.3f },
- { -4.5f, 1.2f, 3.3f },
- { -4.5f, 1.2f, 0 },
- { -4.5f, 1.2f, 3.3f },
- { 4.5f, 0, 3.3f },
- { 0, 1.2f, 3.3f }
- };
-
- for (size_t i = 0; i < base::size(single_values); ++i) {
- Vector2dF v(single_values[i][0], single_values[i][1]);
- v.Scale(single_values[i][2]);
- EXPECT_EQ(v.x(), single_values[i][0] * single_values[i][2]);
- EXPECT_EQ(v.y(), single_values[i][1] * single_values[i][2]);
-
- Vector2dF v2 = ScaleVector2d(
- gfx::Vector2dF(double_values[i][0], double_values[i][1]),
- double_values[i][2]);
- EXPECT_EQ(single_values[i][0] * single_values[i][2], v2.x());
- EXPECT_EQ(single_values[i][1] * single_values[i][2], v2.y());
- }
+ EXPECT_EQ(Vector2d(0, 0), -Vector2d(0, 0));
+ EXPECT_EQ(Vector2d(-3, -3), -Vector2d(3, 3));
+ EXPECT_EQ(Vector2d(3, 3), -Vector2d(-3, -3));
+ EXPECT_EQ(Vector2d(-3, 3), -Vector2d(3, -3));
+ EXPECT_EQ(Vector2d(3, -3), -Vector2d(-3, 3));
}
TEST(Vector2dTest, Length) {
- int int_values[][2] = {
- { 0, 0 },
- { 10, 20 },
- { 20, 10 },
- { -10, -20 },
- { -20, 10 },
- { 10, -20 },
+ int values[][2] = {
+ {0, 0}, {10, 20}, {20, 10}, {-10, -20}, {-20, 10}, {10, -20},
};
- for (size_t i = 0; i < base::size(int_values); ++i) {
- int v0 = int_values[i][0];
- int v1 = int_values[i][1];
+ for (auto& value : values) {
+ int v0 = value[0];
+ int v1 = value[1];
double length_squared =
static_cast<double>(v0) * v0 + static_cast<double>(v1) * v1;
double length = std::sqrt(length_squared);
@@ -171,82 +51,32 @@
EXPECT_EQ(static_cast<float>(length_squared), vector.LengthSquared());
EXPECT_EQ(static_cast<float>(length), vector.Length());
}
-
- float float_values[][2] = {
- { 0, 0 },
- { 10.5f, 20.5f },
- { 20.5f, 10.5f },
- { -10.5f, -20.5f },
- { -20.5f, 10.5f },
- { 10.5f, -20.5f },
- // A large vector that fails if the Length function doesn't use
- // double precision internally.
- { 1236278317862780234892374893213178027.12122348904204230f,
- 335890352589839028212313231225425134332.38123f },
- };
-
- for (size_t i = 0; i < base::size(float_values); ++i) {
- double v0 = float_values[i][0];
- double v1 = float_values[i][1];
- double length_squared =
- static_cast<double>(v0) * v0 + static_cast<double>(v1) * v1;
- double length = std::sqrt(length_squared);
- Vector2dF vector(v0, v1);
- EXPECT_DOUBLE_EQ(length_squared, vector.LengthSquared());
- EXPECT_FLOAT_EQ(static_cast<float>(length), vector.Length());
- }
}
-TEST(Vector2dTest, ClampVector2d) {
+TEST(Vector2dTest, SetToMinMax) {
Vector2d a;
a = Vector2d(3, 5);
- EXPECT_EQ(Vector2d(3, 5).ToString(), a.ToString());
+ EXPECT_EQ(Vector2d(3, 5), a);
a.SetToMax(Vector2d(2, 4));
- EXPECT_EQ(Vector2d(3, 5).ToString(), a.ToString());
+ EXPECT_EQ(Vector2d(3, 5), a);
a.SetToMax(Vector2d(3, 5));
- EXPECT_EQ(Vector2d(3, 5).ToString(), a.ToString());
+ EXPECT_EQ(Vector2d(3, 5), a);
a.SetToMax(Vector2d(4, 2));
- EXPECT_EQ(Vector2d(4, 5).ToString(), a.ToString());
+ EXPECT_EQ(Vector2d(4, 5), a);
a.SetToMax(Vector2d(8, 10));
- EXPECT_EQ(Vector2d(8, 10).ToString(), a.ToString());
+ EXPECT_EQ(Vector2d(8, 10), a);
a.SetToMin(Vector2d(9, 11));
- EXPECT_EQ(Vector2d(8, 10).ToString(), a.ToString());
+ EXPECT_EQ(Vector2d(8, 10), a);
a.SetToMin(Vector2d(8, 10));
- EXPECT_EQ(Vector2d(8, 10).ToString(), a.ToString());
+ EXPECT_EQ(Vector2d(8, 10), a);
a.SetToMin(Vector2d(11, 9));
- EXPECT_EQ(Vector2d(8, 9).ToString(), a.ToString());
+ EXPECT_EQ(Vector2d(8, 9), a);
a.SetToMin(Vector2d(7, 11));
- EXPECT_EQ(Vector2d(7, 9).ToString(), a.ToString());
+ EXPECT_EQ(Vector2d(7, 9), a);
a.SetToMin(Vector2d(3, 5));
- EXPECT_EQ(Vector2d(3, 5).ToString(), a.ToString());
-}
-
-TEST(Vector2dTest, ClampVector2dF) {
- Vector2dF a;
-
- a = Vector2dF(3.5f, 5.5f);
- EXPECT_EQ(Vector2dF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(Vector2dF(2.5f, 4.5f));
- EXPECT_EQ(Vector2dF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(Vector2dF(3.5f, 5.5f));
- EXPECT_EQ(Vector2dF(3.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(Vector2dF(4.5f, 2.5f));
- EXPECT_EQ(Vector2dF(4.5f, 5.5f).ToString(), a.ToString());
- a.SetToMax(Vector2dF(8.5f, 10.5f));
- EXPECT_EQ(Vector2dF(8.5f, 10.5f).ToString(), a.ToString());
-
- a.SetToMin(Vector2dF(9.5f, 11.5f));
- EXPECT_EQ(Vector2dF(8.5f, 10.5f).ToString(), a.ToString());
- a.SetToMin(Vector2dF(8.5f, 10.5f));
- EXPECT_EQ(Vector2dF(8.5f, 10.5f).ToString(), a.ToString());
- a.SetToMin(Vector2dF(11.5f, 9.5f));
- EXPECT_EQ(Vector2dF(8.5f, 9.5f).ToString(), a.ToString());
- a.SetToMin(Vector2dF(7.5f, 11.5f));
- EXPECT_EQ(Vector2dF(7.5f, 9.5f).ToString(), a.ToString());
- a.SetToMin(Vector2dF(3.5f, 5.5f));
- EXPECT_EQ(Vector2dF(3.5f, 5.5f).ToString(), a.ToString());
+ EXPECT_EQ(Vector2d(3, 5), a);
}
TEST(Vector2dTest, IntegerOverflow) {
@@ -288,6 +118,20 @@
test = Vector2d(-10, -20);
test -= Vector2d(int_max, int_max);
EXPECT_EQ(test, min_vector);
+
+ test = Vector2d();
+ test -= Vector2d(int_min, int_min);
+ EXPECT_EQ(test, max_vector);
+
+ test = -Vector2d(int_min, int_min);
+ EXPECT_EQ(test, max_vector);
+}
+
+TEST(Vector2dTest, Transpose) {
+ gfx::Vector2d v(1, -2);
+ EXPECT_EQ(gfx::Vector2d(-2, 1), TransposeVector2d(v));
+ v.Transpose();
+ EXPECT_EQ(gfx::Vector2d(-2, 1), v);
}
} // namespace gfx
diff --git a/ui/gfx/geometry/vector3d_f.cc b/ui/gfx/geometry/vector3d_f.cc
index d538a57..065d159 100644
--- a/ui/gfx/geometry/vector3d_f.cc
+++ b/ui/gfx/geometry/vector3d_f.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -16,7 +16,7 @@
namespace gfx {
std::string Vector3dF::ToString() const {
- return base::StringPrintf("[%f %f %f]", x_, y_, z_);
+ return base::StringPrintf("[%g %g %g]", x_, y_, z_);
}
bool Vector3dF::IsZero() const {
@@ -50,6 +50,14 @@
z_ *= z_scale;
}
+void Vector3dF::InvScale(float inv_x_scale,
+ float inv_y_scale,
+ float inv_z_scale) {
+ x_ /= inv_x_scale;
+ y_ /= inv_y_scale;
+ z_ /= inv_z_scale;
+}
+
void Vector3dF::Cross(const Vector3dF& other) {
double dx = x_;
double dy = y_;
@@ -67,7 +75,7 @@
*out = *this;
if (length_squared < kEpsilon * kEpsilon)
return false;
- out->Scale(1 / sqrt(length_squared));
+ out->InvScale(sqrt(length_squared));
return true;
}
diff --git a/ui/gfx/geometry/vector3d_f.h b/ui/gfx/geometry/vector3d_f.h
index 8238a16..2174b5f 100644
--- a/ui/gfx/geometry/vector3d_f.h
+++ b/ui/gfx/geometry/vector3d_f.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -68,6 +68,11 @@
// Scale the each component of the vector by the given scale factors.
void Scale(float x_scale, float y_scale, float z_scale);
+ // Divides all components of the vector by |scale|.
+ void InvScale(float inv_scale) { InvScale(inv_scale, inv_scale, inv_scale); }
+ // Divides each component of the vector by the given scale factors.
+ void InvScale(float inv_x_scale, float inv_y_scale, float inv_z_scale);
+
// Take the cross product of this vector with |other| and become the result.
void Cross(const Vector3dF& other);
diff --git a/ui/gfx/geometry/vector3d_unittest.cc b/ui/gfx/geometry/vector3d_f_unittest.cc
similarity index 91%
rename from ui/gfx/geometry/vector3d_unittest.cc
rename to ui/gfx/geometry/vector3d_f_unittest.cc
index 1eab6a6..6493862 100644
--- a/ui/gfx/geometry/vector3d_unittest.cc
+++ b/ui/gfx/geometry/vector3d_f_unittest.cc
@@ -1,20 +1,20 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/gfx/geometry/vector3d_f.h"
+
#include <stddef.h>
#include <cmath>
#include <limits>
-#include "base/cxx17_backports.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/vector3d_f.h"
namespace gfx {
-TEST(Vector3dTest, IsZero) {
+TEST(Vector3dFTest, IsZero) {
gfx::Vector3dF float_zero(0, 0, 0);
gfx::Vector3dF float_nonzero(0.1f, -0.1f, 0.1f);
@@ -22,7 +22,7 @@
EXPECT_FALSE(float_nonzero.IsZero());
}
-TEST(Vector3dTest, Add) {
+TEST(Vector3dFTest, Add) {
gfx::Vector3dF f1(3.1f, 5.1f, 2.7f);
gfx::Vector3dF f2(4.3f, -1.3f, 8.1f);
@@ -35,12 +35,12 @@
{ gfx::Vector3dF(3.1f - 4.3f, 5.1f + 1.3f, 2.7f - 8.1f), f1 - f2 }
};
- for (size_t i = 0; i < base::size(float_tests); ++i)
+ for (size_t i = 0; i < std::size(float_tests); ++i)
EXPECT_EQ(float_tests[i].expected.ToString(),
float_tests[i].actual.ToString());
}
-TEST(Vector3dTest, Negative) {
+TEST(Vector3dFTest, Negative) {
const struct {
gfx::Vector3dF expected;
gfx::Vector3dF actual;
@@ -53,12 +53,12 @@
{ gfx::Vector3dF(-0.3f, -0.3f, 0.3f), -gfx::Vector3dF(0.3f, 0.3f, -0.3f) }
};
- for (size_t i = 0; i < base::size(float_tests); ++i)
+ for (size_t i = 0; i < std::size(float_tests); ++i)
EXPECT_EQ(float_tests[i].expected.ToString(),
float_tests[i].actual.ToString());
}
-TEST(Vector3dTest, Scale) {
+TEST(Vector3dFTest, Scale) {
float triple_values[][6] = {
{ 4.5f, 1.2f, 1.8f, 3.3f, 5.6f, 4.2f },
{ 4.5f, -1.2f, -1.8f, 3.3f, 5.6f, 4.2f },
@@ -86,7 +86,7 @@
{ 0, 1.2f, 1.8f, 3.3f, 5.6f, 4.2f }
};
- for (size_t i = 0; i < base::size(triple_values); ++i) {
+ for (size_t i = 0; i < std::size(triple_values); ++i) {
gfx::Vector3dF v(triple_values[i][0],
triple_values[i][1],
triple_values[i][2]);
@@ -122,7 +122,7 @@
{ 4.5f, 1.2f, 0, 3.3f }
};
- for (size_t i = 0; i < base::size(single_values); ++i) {
+ for (size_t i = 0; i < std::size(single_values); ++i) {
gfx::Vector3dF v(single_values[i][0],
single_values[i][1],
single_values[i][2]);
@@ -142,7 +142,7 @@
}
}
-TEST(Vector3dTest, Length) {
+TEST(Vector3dFTest, Length) {
float float_values[][3] = {
{ 0, 0, 0 },
{ 10.5f, 20.5f, 8.5f },
@@ -164,7 +164,7 @@
27861786423846742743236423478236784678.236713617231f }
};
- for (size_t i = 0; i < base::size(float_values); ++i) {
+ for (size_t i = 0; i < std::size(float_values); ++i) {
double v0 = float_values[i][0];
double v1 = float_values[i][1];
double v2 = float_values[i][2];
@@ -179,7 +179,7 @@
}
}
-TEST(Vector3dTest, DotProduct) {
+TEST(Vector3dFTest, DotProduct) {
const struct {
float expected;
gfx::Vector3dF input1;
@@ -198,13 +198,13 @@
gfx::Vector3dF(1.1f, 2.2f, 3.3f), gfx::Vector3dF(4.4f, 5.5f, 6.6f) }
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
float actual = gfx::DotProduct(tests[i].input1, tests[i].input2);
EXPECT_EQ(tests[i].expected, actual);
}
}
-TEST(Vector3dTest, CrossProduct) {
+TEST(Vector3dFTest, CrossProduct) {
const struct {
gfx::Vector3dF expected;
gfx::Vector3dF input1;
@@ -226,7 +226,7 @@
{ Vector3dF(0, -1, 1), Vector3dF(1, 0, 0), Vector3dF(1, 1, 1) }
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
SCOPED_TRACE(i);
Vector3dF actual = gfx::CrossProduct(tests[i].input1, tests[i].input2);
EXPECT_EQ(tests[i].expected.ToString(), actual.ToString());
@@ -265,7 +265,7 @@
EXPECT_EQ(Vector3dF(3.5f, 5.5f, 7.5f).ToString(), a.ToString());
}
-TEST(Vector3dTest, AngleBetweenVectorsInDegress) {
+TEST(Vector3dFTest, AngleBetweenVectorsInDegress) {
const struct {
float expected;
gfx::Vector3dF input1;
@@ -281,7 +281,7 @@
{0, gfx::Vector3dF(0, -0.990842f, -0.003177f),
gfx::Vector3dF(0, -0.999995f, -0.003124f)}};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
float actual =
gfx::AngleBetweenVectorsInDegrees(tests[i].input1, tests[i].input2);
EXPECT_FLOAT_EQ(tests[i].expected, actual);
@@ -291,7 +291,7 @@
}
}
-TEST(Vector3dTest, ClockwiseAngleBetweenVectorsInDegress) {
+TEST(Vector3dFTest, ClockwiseAngleBetweenVectorsInDegress) {
const struct {
float expected;
gfx::Vector3dF input1;
@@ -308,7 +308,7 @@
const gfx::Vector3dF normal_vector(1.0f, 0.0f, 0.0f);
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
float actual = gfx::ClockwiseAngleBetweenVectorsInDegrees(
tests[i].input1, tests[i].input2, normal_vector);
EXPECT_FLOAT_EQ(tests[i].expected, actual);
@@ -320,7 +320,7 @@
}
}
-TEST(Vector3dTest, GetNormalized) {
+TEST(Vector3dFTest, GetNormalized) {
const struct {
bool expected;
gfx::Vector3dF v;
@@ -339,11 +339,15 @@
gfx::Vector3dF(1, 0, 0)},
};
- for (size_t i = 0; i < base::size(tests); ++i) {
+ for (size_t i = 0; i < std::size(tests); ++i) {
gfx::Vector3dF n;
EXPECT_EQ(tests[i].expected, tests[i].v.GetNormalized(&n));
EXPECT_EQ(tests[i].normalized.ToString(), n.ToString());
}
}
+TEST(Vector3dFTest, ToString) {
+ EXPECT_EQ("[1.03125 2.5 -3]", Vector3dF(1.03125, 2.5, -3).ToString());
+}
+
} // namespace gfx
diff --git a/ui/gfx/geometry_skia_export.h b/ui/gfx/geometry_skia_export.h
index c681982..9245fea 100644
--- a/ui/gfx/geometry_skia_export.h
+++ b/ui/gfx/geometry_skia_export.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/gfx_export.h b/ui/gfx/gfx_export.h
index 20c8bb1..5164a1d 100644
--- a/ui/gfx/gfx_export.h
+++ b/ui/gfx/gfx_export.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/gfx_skia_export.h b/ui/gfx/gfx_skia_export.h
index 5bd3572..7287f48 100644
--- a/ui/gfx/gfx_skia_export.h
+++ b/ui/gfx/gfx_skia_export.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/gpu_extra_info.cc b/ui/gfx/gpu_extra_info.cc
index 90747bf..0b6c77b 100644
--- a/ui/gfx/gpu_extra_info.cc
+++ b/ui/gfx/gpu_extra_info.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/gpu_extra_info.h b/ui/gfx/gpu_extra_info.h
index c895145..e8fa594 100644
--- a/ui/gfx/gpu_extra_info.h
+++ b/ui/gfx/gpu_extra_info.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,20 +8,17 @@
#include <string>
#include <vector>
+#include "build/build_config.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/gfx_export.h"
-#if defined(USE_OZONE)
+#if BUILDFLAG(IS_OZONE)
#include "ui/ozone/buildflags.h"
#if BUILDFLAG(OZONE_PLATFORM_X11)
#define USE_OZONE_PLATFORM_X11
#endif
#endif
-#if defined(USE_X11) || defined(USE_OZONE_PLATFORM_X11)
-#include "ui/gfx/x/xproto.h"
-#endif
-
namespace gfx {
// Specification of a feature that can be enabled/disable in ANGLE
@@ -65,7 +62,7 @@
// applicable.
ANGLEFeatures angle_features;
-#if defined(USE_X11) || defined(USE_OZONE_PLATFORM_X11)
+#if defined(USE_OZONE_PLATFORM_X11)
std::vector<gfx::BufferUsageAndFormat> gpu_memory_buffer_support_x11;
#endif
};
diff --git a/ui/gfx/gpu_fence.cc b/ui/gfx/gpu_fence.cc
index e52f607..77ca117 100644
--- a/ui/gfx/gpu_fence.cc
+++ b/ui/gfx/gpu_fence.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,8 +7,9 @@
#include "base/logging.h"
#include "base/notreached.h"
#include "base/time/time.h"
+#include "build/build_config.h"
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
#include <sync/sync.h>
#endif
@@ -41,7 +42,7 @@
return;
}
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
static const int kInfiniteSyncWaitTimeout = -1;
DCHECK_GE(fence_handle_.owned_fd.get(), 0);
if (sync_wait(fence_handle_.owned_fd.get(), kInfiniteSyncWaitTimeout) < 0) {
@@ -56,7 +57,7 @@
GpuFence::FenceStatus GpuFence::GetStatusChangeTime(int fd,
base::TimeTicks* time) {
DCHECK_NE(fd, -1);
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
auto info =
std::unique_ptr<sync_fence_info_data, void (*)(sync_fence_info_data*)>{
sync_fence_info(fd), sync_fence_info_free};
@@ -88,7 +89,7 @@
base::TimeTicks GpuFence::GetMaxTimestamp() const {
base::TimeTicks timestamp;
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID)
FenceStatus status =
GetStatusChangeTime(fence_handle_.owned_fd.get(), ×tamp);
DCHECK_EQ(status, FenceStatus::kSignaled);
diff --git a/ui/gfx/gpu_fence.h b/ui/gfx/gpu_fence.h
index eb71d7f..86b2af5 100644
--- a/ui/gfx/gpu_fence.h
+++ b/ui/gfx/gpu_fence.h
@@ -1,11 +1,10 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_GPU_FENCE_H_
#define UI_GFX_GPU_FENCE_H_
-#include "base/macros.h"
#include "build/build_config.h"
#include "ui/gfx/gfx_export.h"
#include "ui/gfx/gpu_fence_handle.h"
diff --git a/ui/gfx/gpu_fence_handle.cc b/ui/gfx/gpu_fence_handle.cc
index 85a6e5b..ff5e9ee 100644
--- a/ui/gfx/gpu_fence_handle.cc
+++ b/ui/gfx/gpu_fence_handle.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,18 +6,19 @@
#include "base/debug/alias.h"
#include "base/notreached.h"
+#include "build/build_config.h"
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
#include <unistd.h>
#include "base/posix/eintr_wrapper.h"
#endif
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
#include "base/fuchsia/fuchsia_logging.h"
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include "base/process/process_handle.h"
#endif
@@ -33,11 +34,11 @@
GpuFenceHandle::~GpuFenceHandle() = default;
bool GpuFenceHandle::is_null() const {
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
return !owned_fd.is_valid();
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
return !owned_event.is_valid();
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
return !owned_handle.IsValid();
#else
return true;
@@ -49,19 +50,19 @@
return GpuFenceHandle();
gfx::GpuFenceHandle handle;
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
const int duped_handle = HANDLE_EINTR(dup(owned_fd.get()));
if (duped_handle < 0)
return GpuFenceHandle();
handle.owned_fd = base::ScopedFD(duped_handle);
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
zx_status_t status =
owned_event.duplicate(ZX_RIGHT_SAME_RIGHTS, &handle.owned_event);
if (status != ZX_OK) {
ZX_DLOG(ERROR, status) << "zx_handle_duplicate";
return GpuFenceHandle();
}
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
const base::ProcessHandle process = ::GetCurrentProcess();
HANDLE duplicated_handle = INVALID_HANDLE_VALUE;
const BOOL result =
diff --git a/ui/gfx/gpu_fence_handle.h b/ui/gfx/gpu_fence_handle.h
index 3e4abef..eaede9f 100644
--- a/ui/gfx/gpu_fence_handle.h
+++ b/ui/gfx/gpu_fence_handle.h
@@ -1,23 +1,22 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_GPU_FENCE_HANDLE_H_
#define UI_GFX_GPU_FENCE_HANDLE_H_
-#include "base/macros.h"
#include "build/build_config.h"
#include "ui/gfx/gfx_export.h"
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
#include "base/files/scoped_file.h"
#endif
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
#include <lib/zx/event.h>
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "base/win/scoped_handle.h"
#endif
@@ -40,11 +39,11 @@
GpuFenceHandle Clone() const;
// TODO(crbug.com/1142962): Make this a class instead of struct.
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
base::ScopedFD owned_fd;
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
zx::event owned_event;
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
base::win::ScopedHandle owned_handle;
#endif
};
diff --git a/ui/gfx/gpu_memory_buffer.cc b/ui/gfx/gpu_memory_buffer.cc
index 44b2667..e28601c 100644
--- a/ui/gfx/gpu_memory_buffer.cc
+++ b/ui/gfx/gpu_memory_buffer.cc
@@ -1,20 +1,21 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/gpu_memory_buffer.h"
#include "base/logging.h"
+#include "build/build_config.h"
#include "ui/gfx/generic_shared_memory_id.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#include "base/win/scoped_handle.h"
#endif
namespace gfx {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
namespace {
base::win::ScopedHandle CloneDXGIHandle(HANDLE handle) {
HANDLE target_handle = nullptr;
@@ -29,7 +30,7 @@
GpuMemoryBufferHandle::GpuMemoryBufferHandle() = default;
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
GpuMemoryBufferHandle::GpuMemoryBufferHandle(
base::android::ScopedHardwareBufferHandle handle)
: type(GpuMemoryBufferType::ANDROID_HARDWARE_BUFFER),
@@ -53,13 +54,14 @@
handle.region = region.Duplicate();
handle.offset = offset;
handle.stride = stride;
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
handle.native_pixmap_handle = CloneHandleForIPC(native_pixmap_handle);
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_APPLE)
handle.io_surface = io_surface;
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
handle.dxgi_handle = CloneDXGIHandle(dxgi_handle.Get());
-#elif defined(OS_ANDROID)
+ handle.dxgi_token = dxgi_token;
+#elif BUILDFLAG(IS_ANDROID)
NOTIMPLEMENTED();
#endif
return handle;
@@ -67,6 +69,4 @@
void GpuMemoryBuffer::SetColorSpace(const ColorSpace& color_space) {}
-void GpuMemoryBuffer::SetHDRMetadata(const HDRMetadata& hdr_metadata) {}
-
} // namespace gfx
diff --git a/ui/gfx/gpu_memory_buffer.h b/ui/gfx/gpu_memory_buffer.h
index 9d6fc35..839a133 100644
--- a/ui/gfx/gpu_memory_buffer.h
+++ b/ui/gfx/gpu_memory_buffer.h
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -14,20 +14,19 @@
#include "ui/gfx/generic_shared_memory_id.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/hdr_metadata.h"
-#if defined(USE_OZONE) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_OZONE) || BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "ui/gfx/native_pixmap_handle.h"
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_APPLE)
#include "ui/gfx/mac/io_surface.h"
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
+#include "base/types/token_type.h"
#include "base/win/scoped_handle.h"
-#elif defined(OS_ANDROID)
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#elif BUILDFLAG(IS_ANDROID)
#include "base/android/scoped_hardware_buffer_handle.h"
#endif
-extern "C" typedef struct _ClientBuffer* ClientBuffer;
-
namespace base {
namespace trace_event {
class ProcessMemoryDump;
@@ -51,12 +50,18 @@
using GpuMemoryBufferId = GenericSharedMemoryId;
+#if BUILDFLAG(IS_WIN)
+using DXGIHandleToken = base::TokenType<class DXGIHandleTokenTypeMarker>;
+#endif
+
// TODO(crbug.com/863011): Convert this to a proper class to ensure the state is
// always consistent, particularly that the only one handle is set at the same
// time and it corresponds to |type|.
struct GFX_EXPORT GpuMemoryBufferHandle {
+ static constexpr GpuMemoryBufferId kInvalidId = GpuMemoryBufferId(-1);
+
GpuMemoryBufferHandle();
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
explicit GpuMemoryBufferHandle(
base::android::ScopedHardwareBufferHandle handle);
#endif
@@ -69,14 +74,15 @@
GpuMemoryBufferId id{0};
base::UnsafeSharedMemoryRegion region;
uint32_t offset = 0;
- int32_t stride = 0;
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
+ uint32_t stride = 0;
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_FUCHSIA)
NativePixmapHandle native_pixmap_handle;
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_APPLE)
ScopedIOSurface io_surface;
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
base::win::ScopedHandle dxgi_handle;
-#elif defined(OS_ANDROID)
+ absl::optional<DXGIHandleToken> dxgi_token;
+#elif BUILDFLAG(IS_ANDROID)
base::android::ScopedHardwareBufferHandle android_hardware_buffer;
#endif
};
@@ -116,10 +122,6 @@
// as an overlay. Note that this will not impact texturing from the buffer.
virtual void SetColorSpace(const ColorSpace& color_space);
- // Set the HDR metadata for use when this buffer is used as an overlay. Note
- // that this will not impact texturing from the buffer.
- virtual void SetHDRMetadata(const HDRMetadata& hdr_metadata);
-
// Returns a unique identifier associated with buffer.
virtual GpuMemoryBufferId GetId() const = 0;
@@ -131,9 +133,6 @@
// caller takes ownership of the returned handle.
virtual GpuMemoryBufferHandle CloneHandle() const = 0;
- // Type-checking downcast routine.
- virtual ClientBuffer AsClientBuffer() = 0;
-
// Dumps information about the memory backing the GpuMemoryBuffer to |pmd|.
// The memory usage is attributed to |buffer_dump_guid|.
// |tracing_process_id| uniquely identifies the process owning the memory.
diff --git a/ui/gfx/half_float.cc b/ui/gfx/half_float.cc
index a7c6696..a1d78d0 100644
--- a/ui/gfx/half_float.cc
+++ b/ui/gfx/half_float.cc
@@ -1,7 +1,9 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <cstring>
+
#include "ui/gfx/half_float.h"
namespace gfx {
@@ -9,7 +11,9 @@
void FloatToHalfFloat(const float* input, HalfFloat* output, size_t num) {
for (size_t i = 0; i < num; i++) {
float tmp = input[i] * 1.9259299444e-34f;
- uint32_t tmp2 = *reinterpret_cast<uint32_t*>(&tmp) + (1 << 12);
+ uint32_t tmp2;
+ std::memcpy(&tmp2, &tmp, 4);
+ tmp2 += (1 << 12);
output[i] = (tmp2 & 0x80000000UL) >> 16 | (tmp2 >> 13);
}
}
diff --git a/ui/gfx/half_float.h b/ui/gfx/half_float.h
index c5e48ce..fb7ce3d 100644
--- a/ui/gfx/half_float.h
+++ b/ui/gfx/half_float.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/half_float_unittest.cc b/ui/gfx/half_float_unittest.cc
index d6a1965..50f36bf 100644
--- a/ui/gfx/half_float_unittest.cc
+++ b/ui/gfx/half_float_unittest.cc
@@ -1,12 +1,12 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/gfx/half_float.h"
+
#include <math.h>
-#include "base/cxx17_backports.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/half_float.h"
namespace gfx {
@@ -75,7 +75,7 @@
0.0f, 1.0f, 10.0f, 1000.0f, 65503.0f,
1.0E-3f, 1.0E-6f, 1.0E-20f, 1.0E-44f,
};
- for (size_t i = 0; i < base::size(test); i++) {
+ for (size_t i = 0; i < std::size(test); i++) {
EXPECT_EQ(ConvertTruth(test[i]), Convert(test[i])) << " float = "
<< test[i];
if (test[i] != 0.0) {
diff --git a/ui/gfx/harfbuzz_font_skia.cc b/ui/gfx/harfbuzz_font_skia.cc
index 7b13a18..9958dee 100644
--- a/ui/gfx/harfbuzz_font_skia.cc
+++ b/ui/gfx/harfbuzz_font_skia.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,9 +11,9 @@
#include <map>
#include "base/check_op.h"
-#include "base/containers/mru_cache.h"
+#include "base/containers/lru_cache.h"
#include "base/lazy_instance.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
#include "base/no_destructor.h"
#include "build/build_config.h"
#include "third_party/skia/include/core/SkFont.h"
@@ -37,7 +37,7 @@
explicit FontData(GlyphCache* glyph_cache) : glyph_cache_(glyph_cache) {}
SkFont font_;
- GlyphCache* glyph_cache_;
+ raw_ptr<GlyphCache> glyph_cache_;
};
// Deletes the object at the given pointer after casting it to the given type.
@@ -206,7 +206,7 @@
hb_font_funcs_t* get() { return font_funcs_; }
private:
- hb_font_funcs_t* font_funcs_;
+ raw_ptr<hb_font_funcs_t> font_funcs_;
};
base::LazyInstance<FontFuncs>::Leaky g_font_funcs = LAZY_INSTANCE_INITIALIZER;
@@ -258,7 +258,7 @@
TypefaceData() = delete;
GlyphCache glyphs_;
- hb_face_t* face_ = nullptr;
+ raw_ptr<hb_face_t> face_ = nullptr;
// The skia typeface must outlive |face_| since it's being used by harfbuzz.
sk_sp<SkTypeface> sk_typeface_;
@@ -272,7 +272,7 @@
const FontRenderParams& params,
bool subpixel_rendering_suppressed) {
// A cache from Skia font to harfbuzz typeface information.
- using TypefaceCache = base::MRUCache<SkFontID, TypefaceData>;
+ using TypefaceCache = base::LRUCache<SkFontID, TypefaceData>;
constexpr int kTypefaceCacheSize = 64;
static base::NoDestructor<TypefaceCache> face_caches(kTypefaceCacheSize);
diff --git a/ui/gfx/harfbuzz_font_skia.h b/ui/gfx/harfbuzz_font_skia.h
index abc6c79..b7ec99c 100644
--- a/ui/gfx/harfbuzz_font_skia.h
+++ b/ui/gfx/harfbuzz_font_skia.h
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/hdr_metadata.cc b/ui/gfx/hdr_metadata.cc
index ed20c0f..0aa1ed4 100644
--- a/ui/gfx/hdr_metadata.cc
+++ b/ui/gfx/hdr_metadata.cc
@@ -1,9 +1,14 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/hdr_metadata.h"
+#include "skia/ext/skcolorspace_primaries.h"
+
+#include <iomanip>
+#include <sstream>
+
namespace gfx {
ColorVolumeMetadata::ColorVolumeMetadata() = default;
@@ -12,8 +17,78 @@
ColorVolumeMetadata& ColorVolumeMetadata::operator=(
const ColorVolumeMetadata& rhs) = default;
+ColorVolumeMetadata::ColorVolumeMetadata(const SkColorSpacePrimaries& primaries,
+ float luminance_max,
+ float luminance_min)
+ : primaries(primaries),
+ luminance_max(luminance_max),
+ luminance_min(luminance_min) {}
+
+std::string ColorVolumeMetadata::ToString() const {
+ std::stringstream ss;
+ ss << std::fixed << std::setprecision(4);
+ ss << "{";
+ ss << "red:[" << primaries.fRX << ", " << primaries.fRY << "], ";
+ ss << "green:[" << primaries.fGX << ", " << primaries.fGY << "], ";
+ ss << "blue:[" << primaries.fBX << ", " << primaries.fBY << "], ";
+ ss << "whitePoint:[" << primaries.fWX << ", " << primaries.fWY << "], ";
+ ss << "minLum:" << luminance_min << ", "
+ << "maxLum:" << luminance_max;
+ ss << "}";
+ return ss.str();
+}
+
HDRMetadata::HDRMetadata() = default;
+HDRMetadata::HDRMetadata(const ColorVolumeMetadata& color_volume_metadata,
+ unsigned max_content_light_level,
+ unsigned max_frame_average_light_level)
+ : color_volume_metadata(color_volume_metadata),
+ max_content_light_level(max_content_light_level),
+ max_frame_average_light_level(max_frame_average_light_level) {}
HDRMetadata::HDRMetadata(const HDRMetadata& rhs) = default;
HDRMetadata& HDRMetadata::operator=(const HDRMetadata& rhs) = default;
+// static
+HDRMetadata HDRMetadata::PopulateUnspecifiedWithDefaults(
+ const absl::optional<gfx::HDRMetadata>& hdr_metadata) {
+ const HDRMetadata defaults(
+ ColorVolumeMetadata(SkNamedPrimariesExt::kRec2020, 10000.f, 0.f), 0, 0);
+
+ if (!hdr_metadata)
+ return defaults;
+
+ HDRMetadata result = *hdr_metadata;
+
+ // If the gamut is unspecified, replace it with the default Rec2020.
+ if (result.color_volume_metadata.primaries == SkNamedPrimariesExt::kInvalid) {
+ result.color_volume_metadata.primaries =
+ defaults.color_volume_metadata.primaries;
+ }
+
+ // If the max luminance is unspecified, replace it with the default 10,000
+ // nits.
+ if (result.color_volume_metadata.luminance_max == 0.f) {
+ result.color_volume_metadata.luminance_max =
+ defaults.color_volume_metadata.luminance_max;
+ }
+
+ return result;
+}
+
+std::string HDRMetadata::ToString() const {
+ std::stringstream ss;
+ ss << "{";
+ ss << "smpteSt2086:" << color_volume_metadata.ToString() << ", ";
+ ss << "maxCLL:" << max_content_light_level << ", ";
+ ss << "maxFALL:" << max_frame_average_light_level;
+
+ if (extended_range_brightness) {
+ ss << "cur_ratio: " << extended_range_brightness->current_buffer_ratio;
+ ss << "desired_ratio: " << extended_range_brightness->desired_ratio;
+ }
+
+ ss << "}";
+ return ss.str();
+}
+
} // namespace gfx
diff --git a/ui/gfx/hdr_metadata.h b/ui/gfx/hdr_metadata.h
index 8828158..fbc0742 100644
--- a/ui/gfx/hdr_metadata.h
+++ b/ui/gfx/hdr_metadata.h
@@ -1,39 +1,82 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_HDR_METADATA_H_
#define UI_GFX_HDR_METADATA_H_
-#include "media/base/media_export.h"
+#include <stdint.h>
+#include <string>
+
+#include "skia/ext/skcolorspace_primaries.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/color_space_export.h"
#include "ui/gfx/geometry/point_f.h"
+struct SkColorSpacePrimaries;
+
namespace gfx {
+// High dynamic range mode.
+enum class HDRMode : uint8_t {
+ // HLG and PQ content is HDR and tone mapped. All other content is clipped to
+ // SDR luminance.
+ kDefault,
+ // Values that extend beyond SDR luminance are shown as HDR. No tone mapping
+ // is performed.
+ kExtended,
+};
+
// SMPTE ST 2086 color volume metadata.
-struct MEDIA_EXPORT ColorVolumeMetadata {
- using Chromaticity = gfx::PointF;
- Chromaticity primary_r;
- Chromaticity primary_g;
- Chromaticity primary_b;
- Chromaticity white_point;
+struct COLOR_SPACE_EXPORT ColorVolumeMetadata {
+ SkColorSpacePrimaries primaries = SkNamedPrimariesExt::kInvalid;
float luminance_max = 0;
float luminance_min = 0;
- ColorVolumeMetadata() = default;
- ColorVolumeMetadata(const ColorVolumeMetadata& rhs) = default;
- ColorVolumeMetadata& operator=(const ColorVolumeMetadata& rhs) = default;
+ ColorVolumeMetadata();
+ ColorVolumeMetadata(const ColorVolumeMetadata& rhs);
+ ColorVolumeMetadata(const SkColorSpacePrimaries& primaries,
+ float luminance_max,
+ float luminance_min);
+ ColorVolumeMetadata& operator=(const ColorVolumeMetadata& rhs);
+
+ std::string ToString() const;
bool operator==(const ColorVolumeMetadata& rhs) const {
- return ((primary_r == rhs.primary_r) && (primary_g == rhs.primary_g) &&
- (primary_b == rhs.primary_b) && (white_point == rhs.white_point) &&
- (luminance_max == rhs.luminance_max) &&
- (luminance_min == rhs.luminance_min));
+ return (primaries == rhs.primaries && luminance_max == rhs.luminance_max &&
+ luminance_min == rhs.luminance_min);
+ }
+
+ bool operator!=(const ColorVolumeMetadata& rhs) const {
+ return !(*this == rhs);
+ }
+};
+
+// HDR metadata for extended range color spaces.
+struct COLOR_SPACE_EXPORT ExtendedRangeBrightness {
+ // The current hdr/sdr ratio of the current buffer. For example if the buffer
+ // was rendered with a target SDR whitepoint of 100 nits and a max display
+ // brightness of 200 nits, this should be set to 2.0f.
+ float current_buffer_ratio = 1.0f;
+
+ // The desired hdr/sdr ratio. This can be used to communicate the max desired
+ // brightness range. This is similar to the "max luminance" value in other HDR
+ // metadata formats, but represented as a ratio of the target SDR whitepoint
+ // to the max display brightness.
+ float desired_ratio = 1.0f;
+
+ bool operator==(const ExtendedRangeBrightness& rhs) const {
+ return (current_buffer_ratio == rhs.current_buffer_ratio &&
+ desired_ratio == rhs.desired_ratio);
+ }
+
+ bool operator!=(const ExtendedRangeBrightness& rhs) const {
+ return !(*this == rhs);
}
};
// HDR metadata common for HDR10 and WebM/VP9-based HDR formats.
-struct MEDIA_EXPORT HDRMetadata {
+struct COLOR_SPACE_EXPORT HDRMetadata {
ColorVolumeMetadata color_volume_metadata;
// Max content light level (CLL), i.e. maximum brightness level present in the
// stream), in nits.
@@ -42,21 +85,41 @@
// the brightest frame in the stream), in nits.
unsigned max_frame_average_light_level = 0;
- HDRMetadata() = default;
- HDRMetadata(const HDRMetadata& rhs) = default;
- HDRMetadata& operator=(const HDRMetadata& rhs) = default;
+ // Brightness points for extended range color spaces.
+ // NOTE: Is not serialized over IPC.
+ absl::optional<ExtendedRangeBrightness> extended_range_brightness;
+
+ HDRMetadata();
+ HDRMetadata(const ColorVolumeMetadata& color_volume_metadata,
+ unsigned max_content_light_level,
+ unsigned max_frame_average_light_level);
+ HDRMetadata(const HDRMetadata& rhs);
+ HDRMetadata& operator=(const HDRMetadata& rhs);
bool IsValid() const {
return !((max_content_light_level == 0) &&
(max_frame_average_light_level == 0) &&
- (color_volume_metadata == ColorVolumeMetadata()));
+ (color_volume_metadata == ColorVolumeMetadata()) &&
+ !extended_range_brightness);
}
+ // Return a copy of `hdr_metadata` with its `color_volume_metadata` fully
+ // populated. Any unspecified values are set to default values (in particular,
+ // the gamut is set to rec2020, minimum luminance to 0 nits, and maximum
+ // luminance to 10,000 nits). The `max_content_light_level` and
+ // `max_frame_average_light_level` values are not changed (they may stay
+ // zero).
+ static HDRMetadata PopulateUnspecifiedWithDefaults(
+ const absl::optional<gfx::HDRMetadata>& hdr_metadata);
+
+ std::string ToString() const;
+
bool operator==(const HDRMetadata& rhs) const {
return (
(max_content_light_level == rhs.max_content_light_level) &&
(max_frame_average_light_level == rhs.max_frame_average_light_level) &&
- (color_volume_metadata == rhs.color_volume_metadata));
+ (color_volume_metadata == rhs.color_volume_metadata) &&
+ (extended_range_brightness == rhs.extended_range_brightness));
}
bool operator!=(const HDRMetadata& rhs) const { return !(*this == rhs); }
@@ -64,7 +127,7 @@
// HDR metadata types as described in
// https://w3c.github.io/media-capabilities/#enumdef-hdrmetadatatype
-enum class HdrMetadataType {
+enum class HdrMetadataType : uint8_t {
kNone,
kSmpteSt2086,
kSmpteSt2094_10,
diff --git a/ui/gfx/hdr_metadata_mac.h b/ui/gfx/hdr_metadata_mac.h
new file mode 100644
index 0000000..e96b0c8
--- /dev/null
+++ b/ui/gfx/hdr_metadata_mac.h
@@ -0,0 +1,34 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_HDR_METADATA_MAC_H_
+#define UI_GFX_HDR_METADATA_MAC_H_
+
+#include "base/mac/scoped_cftyperef.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/color_space_export.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+
+namespace gfx {
+
+struct HDRMetadata;
+
+// This can be used for rendering content using AVSampleBufferDisplayLayer via
+// the key kCVImageBufferContentLightLevelInfoKey or for rendering content using
+// a CAMetalLayer via CAEDRMetadata.
+COLOR_SPACE_EXPORT base::ScopedCFTypeRef<CFDataRef>
+GenerateContentLightLevelInfo(
+ const absl::optional<gfx::HDRMetadata>& hdr_metadata);
+
+// This can be used for rendering content using AVSampleBufferDisplayLayer via
+// the key kCVImageBufferMasteringDisplayColorVolumeKey or for rendering content
+// using a CAMetalLayer via CAEDRMetadata.
+COLOR_SPACE_EXPORT base::ScopedCFTypeRef<CFDataRef>
+GenerateMasteringDisplayColorVolume(
+ const absl::optional<gfx::HDRMetadata>& hdr_metadata);
+
+} // namespace gfx
+
+#endif // UI_GFX_HDR_METADATA_MAC_H_
diff --git a/ui/gfx/hdr_metadata_mac.mm b/ui/gfx/hdr_metadata_mac.mm
new file mode 100644
index 0000000..b3ed229
--- /dev/null
+++ b/ui/gfx/hdr_metadata_mac.mm
@@ -0,0 +1,84 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/hdr_metadata_mac.h"
+#include "ui/gfx/hdr_metadata.h"
+
+#include <simd/simd.h>
+
+namespace gfx {
+
+base::ScopedCFTypeRef<CFDataRef> GenerateContentLightLevelInfo(
+ const absl::optional<gfx::HDRMetadata>& hdr_metadata) {
+ if (!hdr_metadata || hdr_metadata->max_content_light_level == 0.f ||
+ hdr_metadata->max_frame_average_light_level == 0.f) {
+ return base::ScopedCFTypeRef<CFDataRef>();
+ }
+
+ // This is a SMPTEST2086 Content Light Level Information box.
+ struct ContentLightLevelInfoSEI {
+ uint16_t max_content_light_level;
+ uint16_t max_frame_average_light_level;
+ } __attribute__((packed, aligned(2)));
+ static_assert(sizeof(ContentLightLevelInfoSEI) == 4, "Must be 4 bytes");
+
+ // Values are stored in big-endian...
+ ContentLightLevelInfoSEI sei;
+ sei.max_content_light_level =
+ __builtin_bswap16(hdr_metadata->max_content_light_level);
+ sei.max_frame_average_light_level =
+ __builtin_bswap16(hdr_metadata->max_frame_average_light_level);
+
+ return base::ScopedCFTypeRef<CFDataRef>(
+ CFDataCreate(nullptr, reinterpret_cast<const UInt8*>(&sei), 4));
+}
+
+base::ScopedCFTypeRef<CFDataRef> GenerateMasteringDisplayColorVolume(
+ const absl::optional<gfx::HDRMetadata>& hdr_metadata) {
+ // This is a SMPTEST2086 Mastering Display Color Volume box.
+ struct MasteringDisplayColorVolumeSEI {
+ vector_ushort2 primaries[3]; // GBR
+ vector_ushort2 white_point;
+ uint32_t luminance_max;
+ uint32_t luminance_min;
+ } __attribute__((packed, aligned(4)));
+ static_assert(sizeof(MasteringDisplayColorVolumeSEI) == 24,
+ "Must be 24 bytes");
+
+ // Make a copy with all values populated, and which we can manipulate.
+ auto md = HDRMetadata::PopulateUnspecifiedWithDefaults(hdr_metadata)
+ .color_volume_metadata;
+
+ constexpr float kColorCoordinateUpperBound = 50000.0f;
+ constexpr float kUnitOfMasteringLuminance = 10000.0f;
+ md.luminance_max *= kUnitOfMasteringLuminance;
+ md.luminance_min *= kUnitOfMasteringLuminance;
+
+ // Values are stored in big-endian...
+ MasteringDisplayColorVolumeSEI sei;
+ const auto& primaries = md.primaries;
+ sei.primaries[0].x =
+ __builtin_bswap16(primaries.fGX * kColorCoordinateUpperBound + 0.5f);
+ sei.primaries[0].y =
+ __builtin_bswap16(primaries.fGY * kColorCoordinateUpperBound + 0.5f);
+ sei.primaries[1].x =
+ __builtin_bswap16(primaries.fBX * kColorCoordinateUpperBound + 0.5f);
+ sei.primaries[1].y =
+ __builtin_bswap16(primaries.fBY * kColorCoordinateUpperBound + 0.5f);
+ sei.primaries[2].x =
+ __builtin_bswap16(primaries.fRX * kColorCoordinateUpperBound + 0.5f);
+ sei.primaries[2].y =
+ __builtin_bswap16(primaries.fRY * kColorCoordinateUpperBound + 0.5f);
+ sei.white_point.x =
+ __builtin_bswap16(primaries.fWX * kColorCoordinateUpperBound + 0.5f);
+ sei.white_point.y =
+ __builtin_bswap16(primaries.fWY * kColorCoordinateUpperBound + 0.5f);
+ sei.luminance_max = __builtin_bswap32(md.luminance_max + 0.5f);
+ sei.luminance_min = __builtin_bswap32(md.luminance_min + 0.5f);
+
+ return base::ScopedCFTypeRef<CFDataRef>(
+ CFDataCreate(nullptr, reinterpret_cast<const UInt8*>(&sei), 24));
+}
+
+} // namespace gfx
diff --git a/ui/gfx/hdr_static_metadata.cc b/ui/gfx/hdr_static_metadata.cc
index b5b3f0a..4f61f8a 100644
--- a/ui/gfx/hdr_static_metadata.cc
+++ b/ui/gfx/hdr_static_metadata.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/hdr_static_metadata.h b/ui/gfx/hdr_static_metadata.h
index 035d3ac..19b2c7a 100644
--- a/ui/gfx/hdr_static_metadata.h
+++ b/ui/gfx/hdr_static_metadata.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/icc_profile.cc b/ui/gfx/icc_profile.cc
index 94f0e7c..5e91553 100644
--- a/ui/gfx/icc_profile.cc
+++ b/ui/gfx/icc_profile.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,12 +8,15 @@
#include <set>
#include "base/command_line.h"
-#include "base/containers/mru_cache.h"
+#include "base/containers/lru_cache.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/synchronization/lock.h"
#include "third_party/skia/include/core/SkColorSpace.h"
-#include "third_party/skia/include/third_party/skcms/skcms.h"
+#include "third_party/skia/include/core/SkData.h"
+#include "third_party/skia/include/core/SkRefCnt.h"
+#include "third_party/skia/include/encode/SkICC.h"
+#include "third_party/skia/modules/skcms/skcms.h"
#include "ui/gfx/skia_color_space_util.h"
namespace gfx {
@@ -22,9 +25,9 @@
static const size_t kMaxCachedICCProfiles = 16;
-// An MRU cache mapping data to ICCProfile objects, to avoid re-parsing
+// An LRU cache mapping data to ICCProfile objects, to avoid re-parsing
// profiles every time they are read.
-using DataToProfileCacheBase = base::MRUCache<std::vector<char>, ICCProfile>;
+using DataToProfileCacheBase = base::LRUCache<std::vector<char>, ICCProfile>;
class DataToProfileCache : public DataToProfileCacheBase {
public:
DataToProfileCache() : DataToProfileCacheBase(kMaxCachedICCProfiles) {}
@@ -173,8 +176,7 @@
if (!internals_ || !internals_->is_valid_)
return ColorSpace();
- return ColorSpace(ColorSpace::PrimaryID::CUSTOM,
- ColorSpace::TransferID::IEC61966_2_1,
+ return ColorSpace(ColorSpace::PrimaryID::CUSTOM, ColorSpace::TransferID::SRGB,
ColorSpace::MatrixID::RGB, ColorSpace::RangeID::FULL,
&internals_->to_XYZD50_, nullptr);
}
diff --git a/ui/gfx/icc_profile.h b/ui/gfx/icc_profile.h
index 542f703..d8da4d9 100644
--- a/ui/gfx/icc_profile.h
+++ b/ui/gfx/icc_profile.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,7 +11,11 @@
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
+#if defined(STARBOARD)
#include "third_party/skia/include/third_party/skcms/skcms.h"
+#else // defined(STARBOARD)
+#include "third_party/skia/modules/skcms/skcms.h"
+#endif // defined(STARBOARD)
#include "ui/gfx/color_space.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
diff --git a/ui/gfx/icc_profile_unittest.cc b/ui/gfx/icc_profile_unittest.cc
index 29c4ff8..85f79e8 100644
--- a/ui/gfx/icc_profile_unittest.cc
+++ b/ui/gfx/icc_profile_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -123,16 +123,13 @@
ColorSpace color_space(ColorSpace::PrimaryID::APPLE_GENERIC_RGB,
ColorSpace::TransferID::GAMMA18);
- skia::Matrix44 icc_profile_matrix;
- skia::Matrix44 color_space_matrix;
+ SkM44 icc_profile_matrix = icc_profile.GetPrimaryMatrix();
+ SkM44 color_space_matrix = color_space.GetPrimaryMatrix();
- icc_profile.GetPrimaryMatrix(&icc_profile_matrix);
- color_space.GetPrimaryMatrix(&color_space_matrix);
-
- skia::Matrix44 eye;
- icc_profile_matrix.invert(&eye);
+ SkM44 eye;
+ EXPECT_TRUE(icc_profile_matrix.invert(&eye));
eye.postConcat(color_space_matrix);
- EXPECT_TRUE(SkMatrixIsApproximatelyIdentity(eye));
+ EXPECT_TRUE(SkM44IsApproximatelyIdentity(eye));
}
} // namespace gfx
diff --git a/ui/gfx/icon_util.cc b/ui/gfx/icon_util.cc
index 7da3e2b..dae400d 100644
--- a/ui/gfx/icon_util.cc
+++ b/ui/gfx/icon_util.cc
@@ -1,14 +1,15 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/icon_util.h"
#include "base/check_op.h"
-#include "base/cxx17_backports.h"
#include "base/files/file_util.h"
#include "base/files/important_file_writer.h"
+#include "base/memory/ref_counted_memory.h"
#include "base/notreached.h"
+#include "base/scoped_generic.h"
#include "base/trace_event/trace_event.h"
#include "base/win/resource_util.h"
#include "base/win/scoped_gdi_object.h"
@@ -30,10 +31,13 @@
struct ScopedICONINFO : ICONINFO {
ScopedICONINFO() {
- hbmColor = NULL;
- hbmMask = NULL;
+ hbmColor = nullptr;
+ hbmMask = nullptr;
}
+ ScopedICONINFO(const ScopedICONINFO&) = delete;
+ ScopedICONINFO& operator=(const ScopedICONINFO&) = delete;
+
~ScopedICONINFO() {
if (hbmColor)
::DeleteObject(hbmColor);
@@ -95,14 +99,14 @@
// size order. If an image of exactly 256x256 is specified, it is converted into
// PNG format and stored in |png_bytes|. Images with width or height larger than
// 256 are ignored.
-// |bitmaps| must be an empty vector, and not NULL.
+// |bitmaps| must be an empty vector, and not nullptr.
// Returns true on success, false on failure. This fails if any image in
// |image_family| is not a 32-bit ARGB image, or is otherwise invalid.
void ConvertImageFamilyToBitmaps(
const gfx::ImageFamily& image_family,
std::vector<SkBitmap>* bitmaps,
scoped_refptr<base::RefCountedMemory>* png_bytes) {
- DCHECK(bitmaps != NULL);
+ DCHECK(bitmaps);
DCHECK(bitmaps->empty());
for (gfx::ImageFamily::const_iterator it = image_family.begin();
@@ -152,16 +156,15 @@
256 // Used by Vista onwards for large icons.
};
-const size_t IconUtil::kNumIconDimensions = base::size(kIconDimensions);
+const size_t IconUtil::kNumIconDimensions = std::size(kIconDimensions);
const size_t IconUtil::kNumIconDimensionsUpToMediumSize = 9;
base::win::ScopedHICON IconUtil::CreateHICONFromSkBitmap(
const SkBitmap& bitmap) {
// Only 32 bit ARGB bitmaps are supported. We also try to perform as many
// validations as we can on the bitmap.
- if ((bitmap.colorType() != kN32_SkColorType) ||
- (bitmap.width() <= 0) || (bitmap.height() <= 0) ||
- (bitmap.getPixels() == NULL))
+ if ((bitmap.colorType() != kN32_SkColorType) || (bitmap.width() <= 0) ||
+ (bitmap.height() <= 0) || (bitmap.getPixels() == nullptr))
return base::win::ScopedHICON();
// We start by creating a DIB which we'll use later on in order to create
@@ -171,15 +174,15 @@
BITMAPV5HEADER bitmap_header;
InitializeBitmapHeader(&bitmap_header, bitmap.width(), bitmap.height());
- void* bits = NULL;
- HBITMAP dib;
-
+ void* bits = nullptr;
+ base::win::ScopedBitmap dib;
{
- base::win::ScopedGetDC hdc(NULL);
- dib = ::CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&bitmap_header),
- DIB_RGB_COLORS, &bits, NULL, 0);
+ base::win::ScopedGetDC hdc(nullptr);
+ dib = base::win::ScopedBitmap(
+ ::CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&bitmap_header),
+ DIB_RGB_COLORS, &bits, nullptr, 0));
}
- if (!dib || !bits)
+ if (!dib.is_valid() || !bits)
return base::win::ScopedHICON();
memcpy(bits, bitmap.getPixels(), bitmap.width() * bitmap.height() * 4);
@@ -209,19 +212,17 @@
memset(mask_bits.get(), 0xFF, mask_bits_size);
}
- HBITMAP mono_bitmap = ::CreateBitmap(bitmap.width(), bitmap.height(), 1, 1,
- reinterpret_cast<LPVOID>(mask_bits.get()));
- DCHECK(mono_bitmap);
+ base::win::ScopedBitmap mono_bitmap(
+ ::CreateBitmap(bitmap.width(), bitmap.height(), 1, 1, mask_bits.get()));
+ DCHECK(mono_bitmap.is_valid());
ICONINFO icon_info;
icon_info.fIcon = TRUE;
icon_info.xHotspot = 0;
icon_info.yHotspot = 0;
- icon_info.hbmMask = mono_bitmap;
- icon_info.hbmColor = dib;
+ icon_info.hbmMask = mono_bitmap.get();
+ icon_info.hbmColor = dib.get();
base::win::ScopedHICON icon(CreateIconIndirect(&icon_info));
- ::DeleteObject(dib);
- ::DeleteObject(mono_bitmap);
return icon;
}
@@ -243,7 +244,7 @@
int resource_id) {
// Read the resource directly so we can get the icon image sizes. This data
// will also be used to directly get the PNG bytes for large images.
- void* icon_dir_data = NULL;
+ void* icon_dir_data = nullptr;
size_t icon_dir_size = 0;
if (!base::win::GetResourceFromModule(module, resource_id, RT_GROUP_ICON,
&icon_dir_data, &icon_dir_size)) {
@@ -271,7 +272,7 @@
} else {
// 256x256 icons are stored with width and height set to 0.
// See: http://en.wikipedia.org/wiki/ICO_(file_format)
- void* png_data = NULL;
+ void* png_data = nullptr;
size_t png_size = 0;
if (!base::win::GetResourceFromModule(module, entry->nID, RT_ICON,
&png_data, &png_size)) {
@@ -325,15 +326,14 @@
skia::CreateBitmapHeaderForN32SkBitmap(
bitmap, reinterpret_cast<BITMAPINFOHEADER*>(&icon_bitmap_info));
- base::win::ScopedGetDC dc(NULL);
- base::win::ScopedCreateDC working_dc(CreateCompatibleDC(dc));
- base::win::ScopedGDIObject<HBITMAP> bitmap_handle(
- CreateDIBSection(dc,
- &icon_bitmap_info,
- DIB_RGB_COLORS,
- 0,
- 0,
- 0));
+ base::win::ScopedCreateDC working_dc;
+ base::win::ScopedBitmap bitmap_handle;
+ {
+ base::win::ScopedGetDC dc(nullptr);
+ working_dc = base::win::ScopedCreateDC(CreateCompatibleDC(dc));
+ bitmap_handle = base::win::ScopedBitmap(
+ CreateDIBSection(dc, &icon_bitmap_info, DIB_RGB_COLORS, 0, 0, 0));
+ }
SetDIBits(0, bitmap_handle.get(), 0, bitmap.height(), bitmap.getPixels(),
&icon_bitmap_info, DIB_RGB_COLORS);
@@ -342,8 +342,8 @@
SetBkMode(working_dc.Get(), TRANSPARENT);
SelectObject(working_dc.Get(), old_bitmap);
- base::win::ScopedGDIObject<HBITMAP> mask(
- CreateBitmap(bitmap.width(), bitmap.height(), 1, 1, NULL));
+ base::win::ScopedBitmap mask(
+ CreateBitmap(bitmap.width(), bitmap.height(), 1, 1, nullptr));
ICONINFO ii = {0};
ii.fIcon = FALSE;
ii.xHotspot = hotspot.x();
@@ -379,15 +379,19 @@
// obtain the icon's image.
BITMAPV5HEADER h;
InitializeBitmapHeader(&h, s.width(), s.height());
- HDC hdc = ::GetDC(NULL);
- uint32_t* bits;
- HBITMAP dib = ::CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&h),
- DIB_RGB_COLORS, reinterpret_cast<void**>(&bits), NULL, 0);
- DCHECK(dib);
- HDC dib_dc = CreateCompatibleDC(hdc);
- ::ReleaseDC(NULL, hdc);
- DCHECK(dib_dc);
- HGDIOBJ old_obj = ::SelectObject(dib_dc, dib);
+ void* bits;
+ base::win::ScopedBitmap dib;
+ base::win::ScopedCreateDC dib_dc;
+ {
+ base::win::ScopedGetDC hdc(nullptr);
+ dib = base::win::ScopedBitmap(
+ ::CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&h),
+ DIB_RGB_COLORS, &bits, nullptr, 0));
+ dib_dc = base::win::ScopedCreateDC(CreateCompatibleDC(hdc));
+ }
+ DCHECK(dib.is_valid());
+ DCHECK(dib_dc.IsValid());
+ HGDIOBJ old_obj = ::SelectObject(dib_dc.Get(), dib.get());
// Windows icons are defined using two different masks. The XOR mask, which
// represents the icon image and an AND mask which is a monochrome bitmap
@@ -407,18 +411,20 @@
// We start by drawing the AND mask into our DIB.
size_t num_pixels = s.GetArea();
memset(bits, 0, num_pixels * 4);
- ::DrawIconEx(dib_dc, 0, 0, icon, s.width(), s.height(), 0, NULL, DI_MASK);
+ ::DrawIconEx(dib_dc.Get(), 0, 0, icon, s.width(), s.height(), 0, nullptr,
+ DI_MASK);
// Capture boolean opacity. We may not use it if we find out the bitmap has
// an alpha channel.
std::unique_ptr<bool[]> opaque(new bool[num_pixels]);
for (size_t i = 0; i < num_pixels; ++i)
- opaque[i] = !bits[i];
+ opaque[i] = !static_cast<uint32_t*>(bits)[i];
// Then draw the image itself which is really the XOR mask.
memset(bits, 0, num_pixels * 4);
- ::DrawIconEx(dib_dc, 0, 0, icon, s.width(), s.height(), 0, NULL, DI_NORMAL);
- memcpy(bitmap.getPixels(), static_cast<void*>(bits), num_pixels * 4);
+ ::DrawIconEx(dib_dc.Get(), 0, 0, icon, s.width(), s.height(), 0, nullptr,
+ DI_NORMAL);
+ memcpy(bitmap.getPixels(), bits, num_pixels * 4);
// Finding out whether the bitmap has an alpha channel.
bool bitmap_has_alpha_channel = PixelsHaveAlpha(
@@ -437,9 +443,7 @@
}
}
- ::SelectObject(dib_dc, old_obj);
- ::DeleteObject(dib);
- ::DeleteDC(dib_dc);
+ ::SelectObject(dib_dc.Get(), old_obj);
return bitmap;
}
@@ -573,10 +577,10 @@
ICONIMAGE* icon_image,
DWORD image_offset,
size_t* image_byte_count) {
- DCHECK(icon_dir != NULL);
- DCHECK(icon_image != NULL);
+ DCHECK(icon_dir);
+ DCHECK(icon_image);
DCHECK_GT(image_offset, 0U);
- DCHECK(image_byte_count != NULL);
+ DCHECK(image_byte_count);
DCHECK_LT(bitmap.width(), kLargeIconSize);
DCHECK_LT(bitmap.height(), kLargeIconSize);
diff --git a/ui/gfx/icon_util.h b/ui/gfx/icon_util.h
index 22b2e72..88640e6 100644
--- a/ui/gfx/icon_util.h
+++ b/ui/gfx/icon_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,7 +11,6 @@
#include <memory>
#include <vector>
-#include "base/macros.h"
#include "base/win/scoped_gdi_object.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
@@ -85,11 +84,7 @@
IconUtil& operator=(const IconUtil&) = delete;
// Given an SkBitmap object, the function converts the bitmap to a Windows
- // icon and returns the corresponding HICON handle. If the function cannot
- // convert the bitmap, NULL is returned.
- //
- // The client is responsible for destroying the icon when it is no longer
- // needed by calling ::DestroyIcon().
+ // icon and returns the corresponding HICON handle if conversion succeeds.
static base::win::ScopedHICON CreateHICONFromSkBitmap(const SkBitmap& bitmap);
// Given a valid HICON handle representing an icon, this function converts
diff --git a/ui/gfx/icon_util_unittest.cc b/ui/gfx/icon_util_unittest.cc
index 21c228e..d399811 100644
--- a/ui/gfx/icon_util_unittest.cc
+++ b/ui/gfx/icon_util_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/icon_util_unittests_resource.h b/ui/gfx/icon_util_unittests_resource.h
index 560a0de..54da83a 100644
--- a/ui/gfx/icon_util_unittests_resource.h
+++ b/ui/gfx/icon_util_unittests_resource.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/buffer_w_stream.cc b/ui/gfx/image/buffer_w_stream.cc
index ea9747f..b9d017f 100644
--- a/ui/gfx/image/buffer_w_stream.cc
+++ b/ui/gfx/image/buffer_w_stream.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/buffer_w_stream.h b/ui/gfx/image/buffer_w_stream.h
index 43b555f..f060798 100644
--- a/ui/gfx/image/buffer_w_stream.h
+++ b/ui/gfx/image/buffer_w_stream.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/buffer_w_stream_unittest.cc b/ui/gfx/image/buffer_w_stream_unittest.cc
index 1d7e02c..1eed652 100644
--- a/ui/gfx/image/buffer_w_stream_unittest.cc
+++ b/ui/gfx/image/buffer_w_stream_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/canvas_image_source.cc b/ui/gfx/image/canvas_image_source.cc
index 13274ed..23a825c 100644
--- a/ui/gfx/image/canvas_image_source.cc
+++ b/ui/gfx/image/canvas_image_source.cc
@@ -1,16 +1,17 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/image/canvas_image_source.h"
#include "base/check_op.h"
-#include "cc/paint/display_item_list.h"
+#include "cc/paint/paint_op_buffer.h"
#include "cc/paint/record_paint_canvas.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/switches.h"
namespace gfx {
@@ -52,28 +53,18 @@
CanvasImageSource::CanvasImageSource(const Size& size) : size_(size) {}
ImageSkiaRep CanvasImageSource::GetImageForScale(float scale) {
- scoped_refptr<cc::DisplayItemList> display_item_list =
- base::MakeRefCounted<cc::DisplayItemList>(
- cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer);
- display_item_list->StartPaint();
-
- SizeF size_in_pixel = ScaleSize(SizeF(size_), scale);
- cc::RecordPaintCanvas record_canvas(
- display_item_list.get(),
- SkRect::MakeWH(SkFloatToScalar(size_in_pixel.width()),
- SkFloatToScalar(size_in_pixel.height())));
+ Size size_in_pixel = ScaleToCeiledSize(size_, scale);
+ cc::InspectableRecordPaintCanvas record_canvas(size_in_pixel);
gfx::Canvas canvas(&record_canvas, scale);
#if DCHECK_IS_ON()
Rect clip_rect;
DCHECK(canvas.GetClipBounds(&clip_rect));
- DCHECK(clip_rect.Contains(gfx::Rect(ToCeiledSize(size_in_pixel))));
+ DCHECK(clip_rect.Contains(gfx::Rect(size_in_pixel)));
#endif
canvas.Scale(scale, scale);
Draw(&canvas);
- display_item_list->EndPaintOfPairedEnd();
- display_item_list->Finalize();
- return ImageSkiaRep(display_item_list->ReleaseAsRecord(),
+ return ImageSkiaRep(record_canvas.ReleaseAsRecord(),
gfx::ScaleToCeiledSize(size_, scale), scale);
}
diff --git a/ui/gfx/image/canvas_image_source.h b/ui/gfx/image/canvas_image_source.h
index 18aeb58..241c3f1 100644
--- a/ui/gfx/image/canvas_image_source.h
+++ b/ui/gfx/image/canvas_image_source.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,8 +7,6 @@
#include <utility>
-#include "base/compiler_specific.h"
-#include "base/macros.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gfx_export.h"
#include "ui/gfx/image/image_skia.h"
diff --git a/ui/gfx/image/image.cc b/ui/gfx/image/image.cc
index 8852ae9..f03a353 100644
--- a/ui/gfx/image/image.cc
+++ b/ui/gfx/image/image.cc
@@ -1,28 +1,31 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/image/image.h"
#include <algorithm>
+#include <map>
+#include <ostream>
#include <utility>
#include <vector>
#include "base/check_op.h"
-#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted_memory.h"
#include "base/notreached.h"
#include "build/build_config.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image_internal.h"
#include "ui/gfx/image/image_platform.h"
#include "ui/gfx/image/image_png_rep.h"
#include "ui/gfx/image/image_skia.h"
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "base/mac/foundation_util.h"
#include "ui/gfx/image/image_skia_util_ios.h"
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
#include "base/mac/foundation_util.h"
#include "base/mac/mac_util.h"
#include "ui/gfx/image/image_skia_util_mac.h"
@@ -30,82 +33,31 @@
namespace gfx {
-namespace {
-
-using RepresentationMap =
- std::map<Image::RepresentationType, std::unique_ptr<internal::ImageRep>>;
-
-} // namespace
-
namespace internal {
-class ImageRepPNG;
-class ImageRepSkia;
-class ImageRepCocoa;
-class ImageRepCocoaTouch;
+ImageRep::ImageRep(Image::RepresentationType rep) : type_(rep) {}
-// An ImageRep is the object that holds the backing memory for an Image. Each
-// RepresentationType has an ImageRep subclass that is responsible for freeing
-// the memory that the ImageRep holds. When an ImageRep is created, it expects
-// to take ownership of the image, without having to retain it or increase its
-// reference count.
-class ImageRep {
- public:
- explicit ImageRep(Image::RepresentationType rep) : type_(rep) {}
+ImageRep::~ImageRep() = default;
- // Deletes the associated pixels of an ImageRep.
- virtual ~ImageRep() {}
+const ImageRepPNG* ImageRep::AsImageRepPNG() const {
+ CHECK_EQ(type_, Image::kImageRepPNG);
+ return reinterpret_cast<const ImageRepPNG*>(this);
+}
+ImageRepPNG* ImageRep::AsImageRepPNG() {
+ return const_cast<ImageRepPNG*>(
+ static_cast<const ImageRep*>(this)->AsImageRepPNG());
+}
- // Cast helpers ("fake RTTI").
- const ImageRepPNG* AsImageRepPNG() const {
- CHECK_EQ(type_, Image::kImageRepPNG);
- return reinterpret_cast<const ImageRepPNG*>(this);
- }
- ImageRepPNG* AsImageRepPNG() {
- return const_cast<ImageRepPNG*>(
- static_cast<const ImageRep*>(this)->AsImageRepPNG());
- }
+const ImageRepSkia* ImageRep::AsImageRepSkia() const {
+ CHECK_EQ(type_, Image::kImageRepSkia);
+ return reinterpret_cast<const ImageRepSkia*>(this);
+}
+ImageRepSkia* ImageRep::AsImageRepSkia() {
+ return const_cast<ImageRepSkia*>(
+ static_cast<const ImageRep*>(this)->AsImageRepSkia());
+}
- const ImageRepSkia* AsImageRepSkia() const {
- CHECK_EQ(type_, Image::kImageRepSkia);
- return reinterpret_cast<const ImageRepSkia*>(this);
- }
- ImageRepSkia* AsImageRepSkia() {
- return const_cast<ImageRepSkia*>(
- static_cast<const ImageRep*>(this)->AsImageRepSkia());
- }
-
-#if defined(OS_IOS)
- const ImageRepCocoaTouch* AsImageRepCocoaTouch() const {
- CHECK_EQ(type_, Image::kImageRepCocoaTouch);
- return reinterpret_cast<const ImageRepCocoaTouch*>(this);
- }
- ImageRepCocoaTouch* AsImageRepCocoaTouch() {
- return const_cast<ImageRepCocoaTouch*>(
- static_cast<const ImageRep*>(this)->AsImageRepCocoaTouch());
- }
-#elif defined(OS_MAC)
- const ImageRepCocoa* AsImageRepCocoa() const {
- CHECK_EQ(type_, Image::kImageRepCocoa);
- return reinterpret_cast<const ImageRepCocoa*>(this);
- }
- ImageRepCocoa* AsImageRepCocoa() {
- return const_cast<ImageRepCocoa*>(
- static_cast<const ImageRep*>(this)->AsImageRepCocoa());
- }
-#endif
-
- Image::RepresentationType type() const { return type_; }
-
- virtual int Width() const = 0;
- virtual int Height() const = 0;
- virtual gfx::Size Size() const = 0;
-
- private:
- Image::RepresentationType type_;
-};
-
-class ImageRepPNG : public ImageRep {
+class ImageRepPNG final : public ImageRep {
public:
ImageRepPNG() : ImageRep(Image::kImageRepPNG) {
}
@@ -116,7 +68,7 @@
ImageRepPNG(const ImageRepPNG&) = delete;
ImageRepPNG& operator=(const ImageRepPNG&) = delete;
- ~ImageRepPNG() override {}
+ ~ImageRepPNG() override = default;
int Width() const override { return Size().width(); }
@@ -125,9 +77,9 @@
gfx::Size Size() const override {
// Read the PNG data to get the image size, caching it.
if (!size_cache_) {
- for (auto it = image_reps().begin(); it != image_reps().end(); ++it) {
- if (it->scale == 1.0f) {
- size_cache_ = it->Size();
+ for (const auto& it : image_reps()) {
+ if (it.scale == 1.0f) {
+ size_cache_ = it.Size();
return *size_cache_;
}
}
@@ -146,7 +98,7 @@
mutable absl::optional<gfx::Size> size_cache_;
};
-class ImageRepSkia : public ImageRep {
+class ImageRepSkia final : public ImageRep {
public:
explicit ImageRepSkia(ImageSkia image)
: ImageRep(Image::kImageRepSkia), image_(image) {}
@@ -154,7 +106,7 @@
ImageRepSkia(const ImageRepSkia&) = delete;
ImageRepSkia& operator=(const ImageRepSkia&) = delete;
- ~ImageRepSkia() override {}
+ ~ImageRepSkia() override = default;
int Width() const override { return image_.width(); }
@@ -169,171 +121,67 @@
ImageSkia image_;
};
-#if defined(OS_IOS)
-class ImageRepCocoaTouch : public ImageRep {
- public:
- explicit ImageRepCocoaTouch(UIImage* image)
- : ImageRep(Image::kImageRepCocoaTouch),
- image_(image) {
- CHECK(image_);
- base::mac::NSObjectRetain(image_);
+ImageStorage::ImageStorage(Image::RepresentationType default_type)
+ : default_representation_type_(default_type)
+#if BUILDFLAG(IS_MAC)
+ ,
+ default_representation_color_space_(base::mac::GetGenericRGBColorSpace())
+#endif // BUILDFLAG(IS_MAC)
+{
+}
+ImageStorage::~ImageStorage() = default;
+
+Image::RepresentationType ImageStorage::default_representation_type() const {
+ DCHECK(IsOnValidSequence());
+ return default_representation_type_;
+}
+
+bool ImageStorage::HasRepresentation(Image::RepresentationType type) const {
+ DCHECK(IsOnValidSequence());
+ return representations_.count(type) != 0;
+}
+
+size_t ImageStorage::RepresentationCount() const {
+ DCHECK(IsOnValidSequence());
+ return representations_.size();
+}
+
+const ImageRep* ImageStorage::GetRepresentation(
+ Image::RepresentationType rep_type,
+ bool must_exist) const {
+ DCHECK(IsOnValidSequence());
+ auto it = representations_.find(rep_type);
+ if (it == representations_.end()) {
+ CHECK(!must_exist);
+ return nullptr;
}
+ return it->second.get();
+}
- ImageRepCocoaTouch(const ImageRepCocoaTouch&) = delete;
- ImageRepCocoaTouch& operator=(const ImageRepCocoaTouch&) = delete;
+const ImageRep* ImageStorage::AddRepresentation(
+ std::unique_ptr<ImageRep> rep) const {
+ DCHECK(IsOnValidSequence());
+ Image::RepresentationType type = rep->type();
+ auto result = representations_.emplace(type, std::move(rep));
- ~ImageRepCocoaTouch() override {
- base::mac::NSObjectRelease(image_);
- image_ = nil;
- }
+ // insert should not fail (implies that there was already a representation
+ // of that type in the map).
+ CHECK(result.second) << "type was already in map.";
- int Width() const override { return Size().width(); }
-
- int Height() const override { return Size().height(); }
-
- gfx::Size Size() const override { return internal::UIImageSize(image_); }
-
- UIImage* image() const { return image_; }
-
- private:
- UIImage* image_;
-};
-#elif defined(OS_MAC)
-class ImageRepCocoa : public ImageRep {
- public:
- explicit ImageRepCocoa(NSImage* image)
- : ImageRep(Image::kImageRepCocoa),
- image_(image) {
- CHECK(image_);
- base::mac::NSObjectRetain(image_);
- }
-
- ImageRepCocoa(const ImageRepCocoa&) = delete;
- ImageRepCocoa& operator=(const ImageRepCocoa&) = delete;
-
- ~ImageRepCocoa() override {
- base::mac::NSObjectRelease(image_);
- image_ = nil;
- }
-
- int Width() const override { return Size().width(); }
-
- int Height() const override { return Size().height(); }
-
- gfx::Size Size() const override { return internal::NSImageSize(image_); }
-
- NSImage* image() const { return image_; }
-
- private:
- NSImage* image_;
-};
-#endif // defined(OS_MAC)
-
-// The Storage class acts similarly to the pixels in a SkBitmap: the Image
-// class holds a refptr instance of Storage, which in turn holds all the
-// ImageReps. This way, the Image can be cheaply copied.
-//
-// This class is deliberately not RefCountedThreadSafe. Making it so does not
-// solve threading issues, as gfx::Image and its internal classes are
-// themselves not threadsafe.
-class ImageStorage : public base::RefCounted<ImageStorage> {
- public:
- explicit ImageStorage(Image::RepresentationType default_type)
- : default_representation_type_(default_type)
-#if defined(OS_MAC)
- ,
- default_representation_color_space_(
- base::mac::GetGenericRGBColorSpace())
-#endif // defined(OS_MAC)
- {
- }
-
- ImageStorage(const ImageStorage&) = delete;
- ImageStorage& operator=(const ImageStorage&) = delete;
-
- Image::RepresentationType default_representation_type() const {
- DCHECK(IsOnValidSequence());
- return default_representation_type_;
- }
-
- bool HasRepresentation(Image::RepresentationType type) const {
- DCHECK(IsOnValidSequence());
- return representations_.count(type) != 0;
- }
-
- size_t RepresentationCount() const {
- DCHECK(IsOnValidSequence());
- return representations_.size();
- }
-
- const ImageRep* GetRepresentation(Image::RepresentationType rep_type,
- bool must_exist) const {
- DCHECK(IsOnValidSequence());
- RepresentationMap::const_iterator it = representations_.find(rep_type);
- if (it == representations_.end()) {
- CHECK(!must_exist);
- return nullptr;
- }
- return it->second.get();
- }
-
- const ImageRep* AddRepresentation(std::unique_ptr<ImageRep> rep) const {
- DCHECK(IsOnValidSequence());
- Image::RepresentationType type = rep->type();
- auto result = representations_.emplace(type, std::move(rep));
-
- // insert should not fail (implies that there was already a representation
- // of that type in the map).
- CHECK(result.second) << "type was already in map.";
-
- return result.first->second.get();
- }
-
-#if defined(OS_MAC)
- void set_default_representation_color_space(CGColorSpaceRef color_space) {
- DCHECK(IsOnValidSequence());
- default_representation_color_space_ = color_space;
- }
- CGColorSpaceRef default_representation_color_space() const {
- DCHECK(IsOnValidSequence());
- return default_representation_color_space_;
- }
-#endif // defined(OS_MAC)
-
- private:
- friend class base::RefCounted<ImageStorage>;
-
- ~ImageStorage() {}
-
- // The type of image that was passed to the constructor. This key will always
- // exist in the |representations_| map.
- Image::RepresentationType default_representation_type_;
-
-#if defined(OS_MAC)
- // The default representation's colorspace. This is used for converting to
- // NSImage. This field exists to compensate for PNGCodec not writing or
- // reading colorspace ancillary chunks. (sRGB, iCCP).
- // Not owned.
- CGColorSpaceRef default_representation_color_space_;
-#endif // defined(OS_MAC)
-
- // All the representations of an Image. Size will always be at least one, with
- // more for any converted representations.
- mutable RepresentationMap representations_;
-};
+ return result.first->second.get();
+}
} // namespace internal
-Image::Image() {
// |storage_| is null for empty Images.
-}
+Image::Image() = default;
Image::Image(const std::vector<ImagePNGRep>& image_reps) {
// Do not store obviously invalid ImagePNGReps.
std::vector<ImagePNGRep> filtered;
- for (size_t i = 0; i < image_reps.size(); ++i) {
- if (image_reps[i].raw_data.get() && image_reps[i].raw_data->size())
- filtered.push_back(image_reps[i]);
+ for (const auto& image_rep : image_reps) {
+ if (image_rep.raw_data.get() && image_rep.raw_data->size())
+ filtered.push_back(image_rep);
}
if (filtered.empty())
@@ -350,22 +198,6 @@
}
}
-#if defined(OS_IOS)
-Image::Image(UIImage* image) {
- if (image) {
- storage_ = new internal::ImageStorage(Image::kImageRepCocoaTouch);
- AddRepresentation(std::make_unique<internal::ImageRepCocoaTouch>(image));
- }
-}
-#elif defined(OS_MAC)
-Image::Image(NSImage* image) {
- if (image) {
- storage_ = new internal::ImageStorage(Image::kImageRepCocoa);
- AddRepresentation(std::make_unique<internal::ImageRepCocoa>(image));
- }
-}
-#endif
-
Image::Image(const Image& other) = default;
Image::Image(Image&& other) noexcept = default;
@@ -374,7 +206,7 @@
Image& Image::operator=(Image&& other) noexcept = default;
-Image::~Image() {}
+Image::~Image() = default;
bool Image::operator==(const Image& other) const {
return storage_ == other.storage_;
@@ -403,7 +235,7 @@
return Image();
std::vector<ImagePNGRep> image_reps;
- image_reps.push_back(ImagePNGRep(input, 1.0f));
+ image_reps.emplace_back(input, 1.0f);
return Image(image_reps);
}
@@ -424,21 +256,21 @@
internal::ImageSkiaFromPNG(png_rep->image_reps()));
break;
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
case kImageRepCocoaTouch: {
const internal::ImageRepCocoaTouch* native_rep =
GetRepresentation(kImageRepCocoaTouch, true)
->AsImageRepCocoaTouch();
scoped_rep = std::make_unique<internal::ImageRepSkia>(
- ImageSkia(ImageSkiaFromUIImage(native_rep->image())));
+ ImageSkiaFromUIImage(UIImageOfImageRepCocoaTouch(native_rep)));
break;
}
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
case kImageRepCocoa: {
const internal::ImageRepCocoa* native_rep =
GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
scoped_rep = std::make_unique<internal::ImageRepSkia>(
- ImageSkia(ImageSkiaFromNSImage(native_rep->image())));
+ ImageSkiaFromNSImage(NSImageOfImageRepCocoa(native_rep)));
break;
}
#endif
@@ -451,7 +283,7 @@
return rep->AsImageRepSkia()->image();
}
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
UIImage* Image::ToUIImage() const {
const internal::ImageRep* rep = GetRepresentation(kImageRepCocoaTouch, false);
if (!rep) {
@@ -460,7 +292,7 @@
case kImageRepPNG: {
const internal::ImageRepPNG* png_rep =
GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
- scoped_rep = std::make_unique<internal::ImageRepCocoaTouch>(
+ scoped_rep = internal::MakeImageRepCocoaTouch(
internal::UIImageFromPNG(png_rep->image_reps()));
break;
}
@@ -468,7 +300,7 @@
const internal::ImageRepSkia* skia_rep =
GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
UIImage* image = UIImageFromImageSkia(*skia_rep->image());
- scoped_rep = std::make_unique<internal::ImageRepCocoaTouch>(image);
+ scoped_rep = internal::MakeImageRepCocoaTouch(image);
break;
}
default:
@@ -477,9 +309,9 @@
CHECK(scoped_rep);
rep = AddRepresentation(std::move(scoped_rep));
}
- return rep->AsImageRepCocoaTouch()->image();
+ return UIImageOfImageRepCocoaTouch(rep->AsImageRepCocoaTouch());
}
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
NSImage* Image::ToNSImage() const {
const internal::ImageRep* rep = GetRepresentation(kImageRepCocoa, false);
if (!rep) {
@@ -491,9 +323,8 @@
case kImageRepPNG: {
const internal::ImageRepPNG* png_rep =
GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
- scoped_rep =
- std::make_unique<internal::ImageRepCocoa>(internal::NSImageFromPNG(
- png_rep->image_reps(), default_representation_color_space));
+ scoped_rep = internal::MakeImageRepCocoa(internal::NSImageFromPNG(
+ png_rep->image_reps(), default_representation_color_space));
break;
}
case kImageRepSkia: {
@@ -501,7 +332,7 @@
GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
NSImage* image = NSImageFromImageSkiaWithColorSpace(*skia_rep->image(),
default_representation_color_space);
- scoped_rep = std::make_unique<internal::ImageRepCocoa>(image);
+ scoped_rep = internal::MakeImageRepCocoa(image);
break;
}
default:
@@ -510,7 +341,7 @@
CHECK(scoped_rep);
rep = AddRepresentation(std::move(scoped_rep));
}
- return rep->AsImageRepCocoa()->image();
+ return NSImageOfImageRepCocoa(rep->AsImageRepCocoa());
}
#endif
@@ -523,28 +354,29 @@
if (rep) {
const std::vector<ImagePNGRep>& image_png_reps =
rep->AsImageRepPNG()->image_reps();
- for (size_t i = 0; i < image_png_reps.size(); ++i) {
- if (image_png_reps[i].scale == 1.0f)
- return image_png_reps[i].raw_data;
+ for (const auto& image_png_rep : image_png_reps) {
+ if (image_png_rep.scale == 1.0f)
+ return image_png_rep.raw_data;
}
return new base::RefCountedBytes();
}
scoped_refptr<base::RefCountedMemory> png_bytes;
switch (DefaultRepresentationType()) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
case kImageRepCocoaTouch: {
const internal::ImageRepCocoaTouch* cocoa_touch_rep =
GetRepresentation(kImageRepCocoaTouch, true)->AsImageRepCocoaTouch();
png_bytes = internal::Get1xPNGBytesFromUIImage(
- cocoa_touch_rep->image());
+ internal::UIImageOfImageRepCocoaTouch(cocoa_touch_rep));
break;
}
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
case kImageRepCocoa: {
const internal::ImageRepCocoa* cocoa_rep =
GetRepresentation(kImageRepCocoa, true)->AsImageRepCocoa();
- png_bytes = internal::Get1xPNGBytesFromNSImage(cocoa_rep->image());
+ png_bytes = internal::Get1xPNGBytesFromNSImage(
+ internal::NSImageOfImageRepCocoa(cocoa_rep));
break;
}
#endif
@@ -571,7 +403,7 @@
// final type eg (converting from ImageRepSkia to ImageRepPNG to get an
// ImageRepCocoa).
std::vector<ImagePNGRep> image_png_reps;
- image_png_reps.push_back(ImagePNGRep(png_bytes, 1.0f));
+ image_png_reps.emplace_back(png_bytes, 1.0f);
AddRepresentation(
base::WrapUnique(new internal::ImageRepPNG(image_png_reps)));
return png_bytes;
@@ -585,7 +417,7 @@
return IsEmpty() ? ImageSkia() : *ToImageSkia();
}
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
NSImage* Image::AsNSImage() const {
return IsEmpty() ? nil : ToNSImage();
}
@@ -621,12 +453,12 @@
return GetRepresentation(DefaultRepresentationType(), true)->Size();
}
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
void Image::SetSourceColorSpace(CGColorSpaceRef color_space) {
if (storage())
storage()->set_default_representation_color_space(color_space);
}
-#endif // defined(OS_MAC)
+#endif // BUILDFLAG(IS_MAC)
Image::RepresentationType Image::DefaultRepresentationType() const {
CHECK(storage());
diff --git a/ui/gfx/image/image.h b/ui/gfx/image/image.h
index 52ad9fd..9cb9b1f 100644
--- a/ui/gfx/image/image.h
+++ b/ui/gfx/image/image.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -21,22 +21,25 @@
#include <stddef.h>
-#include <map>
#include <memory>
#include <vector>
-#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_policy.h"
+#include "base/memory/scoped_refptr.h"
#include "build/build_config.h"
#include "ui/gfx/gfx_export.h"
#include "ui/gfx/native_widget_types.h"
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
typedef struct CGColorSpace* CGColorSpaceRef;
#endif
class SkBitmap;
+namespace base {
+class RefCountedMemory;
+}
+
namespace gfx {
struct ImagePNGRep;
class ImageSkia;
@@ -67,10 +70,10 @@
// representation.
explicit Image(const ImageSkia& image);
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// Retains |image|.
explicit Image(UIImage* image);
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
// Retains |image|.
explicit Image(NSImage* image);
#endif
@@ -118,9 +121,9 @@
// the Image. Must only be called if IsEmpty() is false.
const SkBitmap* ToSkBitmap() const;
const ImageSkia* ToImageSkia() const;
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
UIImage* ToUIImage() const;
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
NSImage* ToNSImage() const;
#endif
@@ -138,7 +141,7 @@
ImageSkia AsImageSkia() const;
// Same as ToNSImage(), but returns nil if this image is empty.
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
NSImage* AsNSImage() const;
#endif
@@ -156,12 +159,12 @@
int Height() const;
gfx::Size Size() const;
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
// Set the default representation's color space. This is used for converting
// to NSImage. This is used to compensate for PNGCodec not writing or reading
// colorspace ancillary chunks. (sRGB, iCCP).
void SetSourceColorSpace(CGColorSpaceRef color_space);
-#endif // defined(OS_MAC)
+#endif // BUILDFLAG(IS_MAC)
private:
// Returns the type of the default representation.
diff --git a/ui/gfx/image/image_family.cc b/ui/gfx/image/image_family.cc
index e6fce1d..783de29 100644
--- a/ui/gfx/image/image_family.cc
+++ b/ui/gfx/image/image_family.cc
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,7 @@
#include <cmath>
+#include "base/check_op.h"
#include "skia/ext/image_operations.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h"
diff --git a/ui/gfx/image/image_family.h b/ui/gfx/image/image_family.h
index f874426..b9bbcdc 100644
--- a/ui/gfx/image/image_family.h
+++ b/ui/gfx/image/image_family.h
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -41,9 +41,14 @@
public:
// Type for iterating over all images in the family, in order.
// Dereferencing this iterator returns a gfx::Image.
- class GFX_EXPORT const_iterator :
- std::iterator<std::bidirectional_iterator_tag, const gfx::Image> {
+ class GFX_EXPORT const_iterator {
public:
+ using iterator_category = std::bidirectional_iterator_tag;
+ using value_type = const gfx::Image;
+ using difference_type = std::ptrdiff_t;
+ using pointer = const gfx::Image*;
+ using reference = const gfx::Image&;
+
const_iterator();
const_iterator(const const_iterator& other);
diff --git a/ui/gfx/image/image_family_unittest.cc b/ui/gfx/image/image_family_unittest.cc
index 4bd2dc6..54d5256 100644
--- a/ui/gfx/image/image_family_unittest.cc
+++ b/ui/gfx/image/image_family_unittest.cc
@@ -1,10 +1,11 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkImageInfo.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_family.h"
#include "ui/gfx/image/image_skia.h"
diff --git a/ui/gfx/image/image_generic.cc b/ui/gfx/image/image_generic.cc
index f598390..8cf1f22 100644
--- a/ui/gfx/image/image_generic.cc
+++ b/ui/gfx/image/image_generic.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/image/image_skia_source.h"
namespace gfx {
diff --git a/ui/gfx/image/image_internal.h b/ui/gfx/image/image_internal.h
new file mode 100644
index 0000000..1226b33
--- /dev/null
+++ b/ui/gfx/image/image_internal.h
@@ -0,0 +1,129 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This holds internal declarations for the machinery of gfx::Image. These are
+// only for the internal use of gfx::Image; do not use them elsewhere.
+
+#ifndef UI_GFX_IMAGE_IMAGE_INTERNAL_H_
+#define UI_GFX_IMAGE_IMAGE_INTERNAL_H_
+
+#include <map>
+#include <memory>
+
+#include "base/memory/ref_counted.h"
+#include "build/build_config.h"
+#include "ui/gfx/image/image.h"
+
+#if BUILDFLAG(IS_MAC)
+#include <CoreGraphics/CoreGraphics.h>
+#endif
+
+namespace gfx::internal {
+
+class ImageRepPNG;
+class ImageRepSkia;
+class ImageRepCocoa;
+class ImageRepCocoaTouch;
+
+// An ImageRep is the object that holds the backing memory for an Image. Each
+// RepresentationType has an ImageRep subclass that is responsible for freeing
+// the memory that the ImageRep holds. When an ImageRep is created, it expects
+// to take ownership of the image, without having to retain it or increase its
+// reference count.
+class ImageRep {
+ public:
+ ImageRep(const ImageRep&) = delete;
+ ImageRep& operator=(const ImageRep&) = delete;
+
+ // Deletes the associated pixels of an ImageRep.
+ virtual ~ImageRep();
+
+ // Cast helpers ("fake RTTI").
+ const ImageRepPNG* AsImageRepPNG() const;
+ ImageRepPNG* AsImageRepPNG();
+
+ const ImageRepSkia* AsImageRepSkia() const;
+ ImageRepSkia* AsImageRepSkia();
+
+#if BUILDFLAG(IS_IOS)
+ const ImageRepCocoaTouch* AsImageRepCocoaTouch() const;
+ ImageRepCocoaTouch* AsImageRepCocoaTouch();
+#elif BUILDFLAG(IS_MAC)
+ const ImageRepCocoa* AsImageRepCocoa() const;
+ ImageRepCocoa* AsImageRepCocoa();
+#endif
+
+ Image::RepresentationType type() const { return type_; }
+
+ virtual int Width() const = 0;
+ virtual int Height() const = 0;
+ virtual gfx::Size Size() const = 0;
+
+ protected:
+ explicit ImageRep(Image::RepresentationType rep);
+
+ private:
+ Image::RepresentationType type_;
+};
+
+// The Storage class acts similarly to the pixels in a SkBitmap: the Image
+// class holds a refptr instance of Storage, which in turn holds all the
+// ImageReps. This way, the Image can be cheaply copied.
+//
+// This class is deliberately not RefCountedThreadSafe. Making it so does not
+// solve threading issues, as gfx::Image and its internal classes are
+// themselves not threadsafe.
+class ImageStorage : public base::RefCounted<ImageStorage> {
+ public:
+ explicit ImageStorage(Image::RepresentationType default_type);
+
+ ImageStorage(const ImageStorage&) = delete;
+ ImageStorage& operator=(const ImageStorage&) = delete;
+
+ Image::RepresentationType default_representation_type() const;
+ bool HasRepresentation(Image::RepresentationType type) const;
+ size_t RepresentationCount() const;
+
+ const ImageRep* GetRepresentation(Image::RepresentationType rep_type,
+ bool must_exist) const;
+ const ImageRep* AddRepresentation(std::unique_ptr<ImageRep> rep) const;
+
+#if BUILDFLAG(IS_MAC)
+ void set_default_representation_color_space(CGColorSpaceRef color_space) {
+ DCHECK(IsOnValidSequence());
+ default_representation_color_space_ = color_space;
+ }
+ CGColorSpaceRef default_representation_color_space() const {
+ DCHECK(IsOnValidSequence());
+ return default_representation_color_space_;
+ }
+#endif // BUILDFLAG(IS_MAC)
+
+ private:
+ friend class base::RefCounted<ImageStorage>;
+
+ ~ImageStorage();
+
+ // The type of image that was passed to the constructor. This key will always
+ // exist in the |representations_| map.
+ Image::RepresentationType default_representation_type_;
+
+#if BUILDFLAG(IS_MAC)
+ // The default representation's colorspace. This is used for converting to
+ // NSImage. This field exists to compensate for PNGCodec not writing or
+ // reading colorspace ancillary chunks. (sRGB, iCCP).
+ // Not owned.
+ CGColorSpaceRef default_representation_color_space_;
+#endif // BUILDFLAG(IS_MAC)
+
+ // All the representations of an Image. Size will always be at least one, with
+ // more for any converted representations.
+ mutable std::map<Image::RepresentationType,
+ std::unique_ptr<internal::ImageRep>>
+ representations_;
+};
+
+} // namespace gfx::internal
+
+#endif // UI_GFX_IMAGE_IMAGE_INTERNAL_H_
diff --git a/ui/gfx/image/image_ios.mm b/ui/gfx/image/image_ios.mm
index a240131..685bf67 100644
--- a/ui/gfx/image/image_ios.mm
+++ b/ui/gfx/image/image_ios.mm
@@ -1,4 +1,4 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,7 @@
#include <stddef.h>
#import <UIKit/UIKit.h>
+
#include <cmath>
#include <limits>
@@ -13,13 +14,12 @@
#include "base/mac/scoped_cftyperef.h"
#include "base/mac/scoped_nsobject.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image_internal.h"
#include "ui/gfx/image/image_png_rep.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/image/image_skia_util_ios.h"
-namespace gfx {
-namespace internal {
-
namespace {
// Returns a 16x16 red UIImage to visually show when a UIImage cannot be
@@ -35,7 +35,9 @@
16, // height
8, // bitsPerComponent
0, // CG will calculate by default.
- color_space, kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
+ color_space,
+ kCGImageAlphaPremultipliedFirst |
+ static_cast<CGImageAlphaInfo>(kCGBitmapByteOrder32Host)));
CGContextSetRGBFillColor(context, 1.0, 0.0, 0.0, 1.0);
CGContextFillRect(context, CGRectMake(0.0, 0.0, 16, 16));
base::ScopedCFTypeRef<CGImageRef> cg_image(
@@ -57,8 +59,51 @@
} // namespace
+namespace gfx {
+
+namespace internal {
+
+class ImageRepCocoaTouch final : public ImageRep {
+ public:
+ explicit ImageRepCocoaTouch(UIImage* image)
+ : ImageRep(Image::kImageRepCocoaTouch),
+ image_(image, base::scoped_policy::RETAIN) {
+ CHECK(image_);
+ }
+
+ ImageRepCocoaTouch(const ImageRepCocoaTouch&) = delete;
+ ImageRepCocoaTouch& operator=(const ImageRepCocoaTouch&) = delete;
+
+ ~ImageRepCocoaTouch() override { image_.reset(); }
+
+ int Width() const override { return Size().width(); }
+
+ int Height() const override { return Size().height(); }
+
+ gfx::Size Size() const override {
+ int width = static_cast<int>(image_.get().size.width);
+ int height = static_cast<int>(image_.get().size.height);
+ return gfx::Size(width, height);
+ }
+
+ UIImage* image() const { return image_; }
+
+ private:
+ base::scoped_nsobject<UIImage> image_;
+};
+
+const ImageRepCocoaTouch* ImageRep::AsImageRepCocoaTouch() const {
+ CHECK_EQ(type_, Image::kImageRepCocoaTouch);
+ return reinterpret_cast<const ImageRepCocoaTouch*>(this);
+}
+ImageRepCocoaTouch* ImageRep::AsImageRepCocoaTouch() {
+ return const_cast<ImageRepCocoaTouch*>(
+ static_cast<const ImageRep*>(this)->AsImageRepCocoaTouch());
+}
+
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage(
UIImage* uiimage) {
+ DCHECK(uiimage);
NSData* data = UIImagePNGRepresentation(uiimage);
if ([data length] == 0)
@@ -113,22 +158,32 @@
// iOS does not expose libpng, so conversion from PNG to ImageSkia must go
// through UIImage.
ImageSkia image_skia;
- for (size_t i = 0; i < image_png_reps.size(); ++i) {
+ for (const auto& image_png_rep : image_png_reps) {
base::scoped_nsobject<UIImage> uiimage(
- CreateUIImageFromImagePNGRep(image_png_reps[i]));
- gfx::ImageSkiaRep image_skia_rep = ImageSkiaRepOfScaleFromUIImage(
- uiimage, image_png_reps[i].scale);
+ CreateUIImageFromImagePNGRep(image_png_rep));
+ gfx::ImageSkiaRep image_skia_rep =
+ ImageSkiaRepOfScaleFromUIImage(uiimage, image_png_rep.scale);
if (!image_skia_rep.is_null())
image_skia.AddRepresentation(image_skia_rep);
}
return image_skia;
}
-gfx::Size UIImageSize(UIImage* image) {
- int width = static_cast<int>(image.size.width);
- int height = static_cast<int>(image.size.height);
- return gfx::Size(width, height);
+UIImage* UIImageOfImageRepCocoaTouch(const ImageRepCocoaTouch* image_rep) {
+ return image_rep->image();
}
-} // namespace internal
-} // namespace gfx
+std::unique_ptr<ImageRep> MakeImageRepCocoaTouch(UIImage* image) {
+ return std::make_unique<internal::ImageRepCocoaTouch>(image);
+}
+
+} // namespace internal
+
+Image::Image(UIImage* image) {
+ if (image) {
+ storage_ = new internal::ImageStorage(Image::kImageRepCocoaTouch);
+ AddRepresentation(std::make_unique<internal::ImageRepCocoaTouch>(image));
+ }
+}
+
+} // namespace gfx
diff --git a/ui/gfx/image/image_ios_unittest.mm b/ui/gfx/image/image_ios_unittest.mm
index c3cd639..f7d8c49 100644
--- a/ui/gfx/image/image_ios_unittest.mm
+++ b/ui/gfx/image/image_ios_unittest.mm
@@ -1,15 +1,16 @@
-// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#import <QuartzCore/QuartzCore.h>
-#include <stddef.h>
-#import <UIKit/UIKit.h>
+#include "ui/gfx/image/image.h"
-#include "base/cxx17_backports.h"
+#import <QuartzCore/QuartzCore.h>
+#import <UIKit/UIKit.h>
+#include <stddef.h>
+
#include "base/mac/scoped_cftyperef.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/image/image.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image_skia.h"
namespace {
@@ -23,13 +24,10 @@
base::ScopedCFTypeRef<CGColorSpaceRef> color_space(
CGColorSpaceCreateDeviceRGB());
base::ScopedCFTypeRef<CGContextRef> context(CGBitmapContextCreate(
- NULL,
- target_size.width,
- target_size.height,
- 8,
- target_size.width * 4,
+ NULL, target_size.width, target_size.height, 8, target_size.width * 4,
color_space,
- kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
+ kCGImageAlphaPremultipliedFirst |
+ static_cast<CGImageAlphaInfo>(kCGBitmapByteOrder32Host)));
CGRect target_rect = CGRectMake(0, 0,
target_size.width, target_size.height);
@@ -73,8 +71,8 @@
const CGFloat kHeight = 100;
const CGFloat kTestScales[3] = { 1.0f, 2.0f, 3.0f };
- for (size_t i = 0; i < base::size(kTestScales); ++i) {
- for (size_t j = 0; j < base::size(kTestScales); ++j) {
+ for (size_t i = 0; i < std::size(kTestScales); ++i) {
+ for (size_t j = 0; j < std::size(kTestScales); ++j) {
const CGFloat source_scale = kTestScales[i];
const CGFloat supported_scale = kTestScales[j];
diff --git a/ui/gfx/image/image_mac.mm b/ui/gfx/image/image_mac.mm
index 939099f..baa2f55 100644
--- a/ui/gfx/image/image_mac.mm
+++ b/ui/gfx/image/image_mac.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,11 +11,9 @@
#include "base/logging.h"
#include "base/mac/scoped_nsobject.h"
#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/image/image_internal.h"
#include "ui/gfx/image/image_png_rep.h"
-namespace gfx {
-namespace internal {
-
namespace {
// Returns a 16x16 red NSImage to visually show when a NSImage cannot be
@@ -33,10 +31,52 @@
} // namespace
+namespace gfx {
+
+namespace internal {
+
+class ImageRepCocoa final : public ImageRep {
+ public:
+ explicit ImageRepCocoa(NSImage* image)
+ : ImageRep(Image::kImageRepCocoa),
+ image_(image, base::scoped_policy::RETAIN) {
+ CHECK(image_);
+ }
+
+ ImageRepCocoa(const ImageRepCocoa&) = delete;
+ ImageRepCocoa& operator=(const ImageRepCocoa&) = delete;
+
+ ~ImageRepCocoa() override { image_.reset(); }
+
+ int Width() const override { return Size().width(); }
+
+ int Height() const override { return Size().height(); }
+
+ gfx::Size Size() const override {
+ int width = static_cast<int>(image_.get().size.width);
+ int height = static_cast<int>(image_.get().size.height);
+ return gfx::Size(width, height);
+ }
+
+ NSImage* image() const { return image_; }
+
+ private:
+ base::scoped_nsobject<NSImage> image_;
+};
+
+const ImageRepCocoa* ImageRep::AsImageRepCocoa() const {
+ CHECK_EQ(type_, Image::kImageRepCocoa);
+ return reinterpret_cast<const ImageRepCocoa*>(this);
+}
+ImageRepCocoa* ImageRep::AsImageRepCocoa() {
+ return const_cast<ImageRepCocoa*>(
+ static_cast<const ImageRep*>(this)->AsImageRepCocoa());
+}
+
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromNSImage(
NSImage* nsimage) {
DCHECK(nsimage);
- CGImageRef cg_image = [nsimage CGImageForProposedRect:NULL
+ CGImageRef cg_image = [nsimage CGImageForProposedRect:nullptr
context:nil
hints:nil];
if (!cg_image) {
@@ -46,7 +86,7 @@
}
base::scoped_nsobject<NSBitmapImageRep> ns_bitmap(
[[NSBitmapImageRep alloc] initWithCGImage:cg_image]);
- NSData* ns_data = [ns_bitmap representationUsingType:NSPNGFileType
+ NSData* ns_data = [ns_bitmap representationUsingType:NSBitmapImageFileTypePNG
properties:@{}];
const unsigned char* bytes =
static_cast<const unsigned char*>([ns_data bytes]);
@@ -64,17 +104,15 @@
}
base::scoped_nsobject<NSImage> image;
- for (size_t i = 0; i < image_png_reps.size(); ++i) {
- scoped_refptr<base::RefCountedMemory> png = image_png_reps[i].raw_data;
+ for (const auto& image_png_rep : image_png_reps) {
+ scoped_refptr<base::RefCountedMemory> png = image_png_rep.raw_data;
CHECK(png.get());
base::scoped_nsobject<NSData> ns_data(
[[NSData alloc] initWithBytes:png->front() length:png->size()]);
base::scoped_nsobject<NSBitmapImageRep> ns_image_rep(
[[NSBitmapImageRep alloc] initWithData:ns_data]);
if (!ns_image_rep) {
- LOG(ERROR) << "Unable to decode PNG at "
- << image_png_reps[i].scale
- << ".";
+ LOG(ERROR) << "Unable to decode PNG at " << image_png_rep.scale << ".";
return GetErrorNSImage();
}
@@ -96,7 +134,7 @@
}
if (!image.get()) {
- float scale = image_png_reps[i].scale;
+ float scale = image_png_rep.scale;
NSSize image_size = NSMakeSize([ns_image_rep pixelsWide] / scale,
[ns_image_rep pixelsHigh] / scale);
image.reset([[NSImage alloc] initWithSize:image_size]);
@@ -107,13 +145,21 @@
return image.autorelease();
}
-gfx::Size NSImageSize(NSImage* image) {
- NSSize size = [image size];
- int width = static_cast<int>(size.width);
- int height = static_cast<int>(size.height);
- return gfx::Size(width, height);
+NSImage* NSImageOfImageRepCocoa(const ImageRepCocoa* image_rep) {
+ return image_rep->image();
}
-} // namespace internal
-} // namespace gfx
+std::unique_ptr<ImageRep> MakeImageRepCocoa(NSImage* image) {
+ return std::make_unique<internal::ImageRepCocoa>(image);
+}
+} // namespace internal
+
+Image::Image(NSImage* image) {
+ if (image) {
+ storage_ = new internal::ImageStorage(Image::kImageRepCocoa);
+ AddRepresentation(std::make_unique<internal::ImageRepCocoa>(image));
+ }
+}
+
+} // namespace gfx
diff --git a/ui/gfx/image/image_mac_unittest.mm b/ui/gfx/image/image_mac_unittest.mm
index 226b61d..e6b0e8b 100644
--- a/ui/gfx/image/image_mac_unittest.mm
+++ b/ui/gfx/image/image_mac_unittest.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,11 +6,11 @@
#include <stddef.h>
#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_png_rep.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/image/image_skia_util_mac.h"
#include "ui/gfx/image/image_unittest_util.h"
diff --git a/ui/gfx/image/image_platform.h b/ui/gfx/image/image_platform.h
index 3e37e8c..7cec0d0 100644
--- a/ui/gfx/image/image_platform.h
+++ b/ui/gfx/image/image_platform.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -21,36 +21,42 @@
#include "ui/gfx/image/image_png_rep.h"
#include "ui/gfx/image/image_skia.h"
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "base/mac/foundation_util.h"
#include "ui/gfx/image/image_skia_util_ios.h"
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
#include "base/mac/foundation_util.h"
#include "base/mac/mac_util.h"
#include "ui/gfx/image/image_skia_util_mac.h"
#endif
-namespace gfx {
-namespace internal {
+namespace gfx::internal {
-#if defined(OS_IOS)
+class ImageRep;
+class ImageRepCocoa;
+class ImageRepCocoaTouch;
+
+#if BUILDFLAG(IS_IOS)
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage(
UIImage* uiimage);
UIImage* UIImageFromPNG(const std::vector<ImagePNGRep>& image_png_reps);
-gfx::Size UIImageSize(UIImage* image);
-#elif defined(OS_MAC)
+
+UIImage* UIImageOfImageRepCocoaTouch(const ImageRepCocoaTouch* image_rep);
+std::unique_ptr<ImageRep> MakeImageRepCocoaTouch(UIImage* image);
+#elif BUILDFLAG(IS_MAC)
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromNSImage(
NSImage* nsimage);
NSImage* NSImageFromPNG(const std::vector<ImagePNGRep>& image_png_reps,
CGColorSpaceRef color_space);
-gfx::Size NSImageSize(NSImage* image);
-#endif // defined(OS_MAC)
+
+NSImage* NSImageOfImageRepCocoa(const ImageRepCocoa* image_rep);
+std::unique_ptr<ImageRep> MakeImageRepCocoa(NSImage* image);
+#endif
ImageSkia ImageSkiaFromPNG(const std::vector<ImagePNGRep>& image_png_reps);
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
const ImageSkia* image_skia);
-} // namespace internal
-} // namespace gfx
+} // namespace gfx::internal
#endif // UI_GFX_IMAGE_IMAGE_PLATFORM_H_
diff --git a/ui/gfx/image/image_png_rep.cc b/ui/gfx/image/image_png_rep.cc
index 4115baf..332d35e 100644
--- a/ui/gfx/image/image_png_rep.cc
+++ b/ui/gfx/image/image_png_rep.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/image_png_rep.h b/ui/gfx/image/image_png_rep.h
index 0a75f19..8715727 100644
--- a/ui/gfx/image/image_png_rep.h
+++ b/ui/gfx/image/image_png_rep.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/image_skia.cc b/ui/gfx/image/image_skia.cc
index a8d7680..d1b8637 100644
--- a/ui/gfx/image/image_skia.cc
+++ b/ui/gfx/image/image_skia.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,22 +6,26 @@
#include <stddef.h>
-#include <algorithm>
#include <cmath>
#include <limits>
#include <memory>
+#include "base/check.h"
#include "base/check_op.h"
#include "base/command_line.h"
+#include "base/containers/contains.h"
#include "base/memory/ptr_util.h"
+#include "base/memory/ref_counted.h"
#include "base/no_destructor.h"
#include "base/sequence_checker.h"
#include "build/build_config.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/image/image_skia_operations.h"
+#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/switches.h"
@@ -39,20 +43,9 @@
// The difference to fall back to the smaller scale factor rather than the
// larger one. For example, assume 1.20 is requested but only 1.0 and 2.0 are
// supported. In that case, not fall back to 2.0 but 1.0, and then expand
-// the image to 1.25.
+// the image to 1.20.
const float kFallbackToSmallerScaleDiff = 0.20f;
-// Maps to the closest supported scale. Returns an exact match, a smaller
-// scale within 0.2 units, the nearest larger scale, or the min/max
-// supported scale.
-float MapToSupportedScale(float scale) {
- for (float supported_scale : *g_supported_scales) {
- if (supported_scale + kFallbackToSmallerScaleDiff >= scale)
- return supported_scale;
- }
- return g_supported_scales->back();
-}
-
} // namespace
namespace internal {
@@ -233,7 +226,6 @@
smallest_diff = diff;
}
}
-
if (fetch_new_image && source_) {
DCHECK(sequence_checker_.CalledOnValidSequence())
<< "An ImageSkia with the source must be accessed by the same "
@@ -246,8 +238,9 @@
ImageSkiaRep image;
float resource_scale = scale;
- if (!HasRepresentationAtAllScales() && g_supported_scales)
- resource_scale = MapToSupportedScale(scale);
+ if (!HasRepresentationAtAllScales()) {
+ resource_scale = ImageSkia::MapToResourceScale(scale);
+ }
if (scale != resource_scale) {
auto iter = FindRepresentation(resource_scale, fetch_new_image);
CHECK(iter != image_reps_.end());
@@ -263,10 +256,7 @@
// If the source returned the new image, store it.
if (!image.is_null() &&
- std::find_if(image_reps_.begin(), image_reps_.end(),
- [&image](const ImageSkiaRep& rep) {
- return rep.scale() == image.scale();
- }) == image_reps_.end()) {
+ !base::Contains(image_reps_, image.scale(), &ImageSkiaRep::scale)) {
mutable_this->image_reps_.push_back(image);
}
@@ -332,12 +322,26 @@
// static
const std::vector<float>& ImageSkia::GetSupportedScales() {
- DCHECK(g_supported_scales != NULL);
+ CHECK_NE(g_supported_scales, nullptr);
return *g_supported_scales;
}
// static
float ImageSkia::GetMaxSupportedScale() {
+ CHECK_NE(g_supported_scales, nullptr);
+ return g_supported_scales->back();
+}
+
+// static
+float ImageSkia::MapToResourceScale(float scale) {
+ CHECK_NE(g_supported_scales, nullptr);
+ // Returns an exact match, a smaller scale within 0.2 units, the nearest
+ // larger scale, or the min/max supported scale.
+ for (float supported_scale : *g_supported_scales) {
+ if (supported_scale + kFallbackToSmallerScaleDiff >= scale) {
+ return supported_scale;
+ }
+ }
return g_supported_scales->back();
}
@@ -507,8 +511,10 @@
void ImageSkia::RemoveUnsupportedRepresentationsForScale(float scale) {
for (const ImageSkiaRep& image_rep_to_test : image_reps()) {
const float test_scale = image_rep_to_test.scale();
- if (test_scale != scale && MapToSupportedScale(test_scale) == scale)
+ if (test_scale != scale &&
+ ImageSkia::MapToResourceScale(test_scale) == scale) {
RemoveRepresentation(test_scale);
+ }
}
}
@@ -528,7 +534,7 @@
// TODO(oshima): This made a few tests flaky on Windows.
// Fix the root cause and re-enable this. crbug.com/145623.
-#if !defined(OS_WIN)
+#if !BUILDFLAG(IS_WIN)
CHECK(CanRead());
#endif
diff --git a/ui/gfx/image/image_skia.h b/ui/gfx/image/image_skia.h
index 156c828..1e8bf4a 100644
--- a/ui/gfx/image/image_skia.h
+++ b/ui/gfx/image/image_skia.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,11 +9,13 @@
#include <vector>
#include "base/gtest_prod_util.h"
-#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_refptr.h"
#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/image/image_skia_rep.h"
+
+class SkBitmap;
namespace gfx {
+class ImageSkiaRep;
class ImageSkiaSource;
class Size;
@@ -53,6 +55,10 @@
// at |scale| and uses its dimensions to calculate the size in DIP.
ImageSkia(std::unique_ptr<ImageSkiaSource> source, float scale);
+ // This constructor is explicitly deleted to ensure callers don't accidentally
+ // pass an int and have it converted to float.
+ ImageSkia(std::unique_ptr<ImageSkiaSource> source, int dont_use) = delete;
+
explicit ImageSkia(const gfx::ImageSkiaRep& image_rep);
// Copies a reference to |other|'s storage.
@@ -73,6 +79,10 @@
// Returns the maximum scale supported by this platform.
static float GetMaxSupportedScale();
+ // Returns the resource scale factor value that ImageSkia uses when
+ // looking for the resource for a given device scale factor.
+ static float MapToResourceScale(float device_scale_factor);
+
// Creates an image from the passed in bitmap, which is designed for display
// at the device scale factor given in `scale`. The DIP width and height will
// be based on that scale factor. A scale factor of 0 is equivalent to
diff --git a/ui/gfx/image/image_skia_operations.cc b/ui/gfx/image/image_skia_operations.cc
index b691b2f..38e361b 100644
--- a/ui/gfx/image/image_skia_operations.cc
+++ b/ui/gfx/image/image_skia_operations.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,7 +9,6 @@
#include "base/command_line.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/numerics/safe_conversions.h"
#include "skia/ext/image_operations.h"
@@ -60,10 +59,7 @@
BinaryImageSource(const ImageSkia& first,
const ImageSkia& second,
const char* source_name)
- : first_(first),
- second_(second),
- source_name_(source_name) {
- }
+ : first_(first), second_(second), source_name_(source_name) {}
BinaryImageSource(const BinaryImageSource&) = delete;
BinaryImageSource& operator=(const BinaryImageSource&) = delete;
@@ -83,7 +79,7 @@
DCHECK_NE(first_rep.scale(), second_rep.scale());
if (first_rep.scale() == second_rep.scale()) {
LOG(ERROR) << "ImageSkiaRep size mismatch in " << source_name_;
- return GetErrorImageRep(first_rep.scale(),first_rep.pixel_size());
+ return GetErrorImageRep(first_rep.scale(), first_rep.pixel_size());
}
first_rep = first_.GetRepresentation(1.0f);
second_rep = second_.GetRepresentation(1.0f);
@@ -119,8 +115,7 @@
const ImageSkia& second,
double alpha)
: BinaryImageSource(first, second, "BlendingImageSource"),
- alpha_(alpha) {
- }
+ alpha_(alpha) {}
BlendingImageSource(const BlendingImageSource&) = delete;
BlendingImageSource& operator=(const BlendingImageSource&) = delete;
@@ -153,8 +148,7 @@
// gfx::CanvasImageSource override.
void Draw(Canvas* canvas) override {
canvas->DrawImageInt(first_, 0, 0);
- canvas->DrawImageInt(second_,
- (first_.width() - second_.width()) / 2,
+ canvas->DrawImageInt(second_, (first_.width() - second_.width()) / 2,
(first_.height() - second_.height()) / 2);
}
@@ -166,9 +160,7 @@
class TransparentImageSource : public gfx::ImageSkiaSource {
public:
TransparentImageSource(const ImageSkia& image, double alpha)
- : image_(image),
- alpha_(alpha) {
- }
+ : image_(image), alpha_(alpha) {}
TransparentImageSource(const TransparentImageSource&) = delete;
TransparentImageSource& operator=(const TransparentImageSource&) = delete;
@@ -183,8 +175,7 @@
return image_rep;
SkBitmap alpha;
- alpha.allocN32Pixels(image_rep.pixel_width(),
- image_rep.pixel_height());
+ alpha.allocN32Pixels(image_rep.pixel_width(), image_rep.pixel_height());
alpha.eraseColor(SkColorSetA(SK_ColorBLACK, SK_AlphaOPAQUE * alpha_));
return ImageSkiaRep(
SkBitmapOperations::CreateMaskedBitmap(image_rep.GetBitmap(), alpha),
@@ -198,8 +189,7 @@
class MaskedImageSource : public BinaryImageSource {
public:
MaskedImageSource(const ImageSkia& rgb, const ImageSkia& alpha)
- : BinaryImageSource(rgb, alpha, "MaskedImageSource") {
- }
+ : BinaryImageSource(rgb, alpha, "MaskedImageSource") {}
MaskedImageSource(const MaskedImageSource&) = delete;
MaskedImageSource& operator=(const MaskedImageSource&) = delete;
@@ -219,14 +209,15 @@
class TiledImageSource : public gfx::ImageSkiaSource {
public:
TiledImageSource(const ImageSkia& source,
- int src_x, int src_y,
- int dst_w, int dst_h)
+ int src_x,
+ int src_y,
+ int dst_w,
+ int dst_h)
: source_(source),
src_x_(src_x),
src_y_(src_y),
dst_w_(dst_w),
- dst_h_(dst_h) {
- }
+ dst_h_(dst_h) {}
TiledImageSource(const TiledImageSource&) = delete;
TiledImageSource& operator=(const TiledImageSource&) = delete;
@@ -239,8 +230,8 @@
if (source_rep.is_null())
return source_rep;
- gfx::Rect bounds = DIPToPixelBounds(gfx::Rect(src_x_, src_y_, dst_w_,
- dst_h_), source_rep.scale());
+ gfx::Rect bounds = DIPToPixelBounds(
+ gfx::Rect(src_x_, src_y_, dst_w_, dst_h_), source_rep.scale());
return ImageSkiaRep(SkBitmapOperations::CreateTiledBitmap(
source_rep.GetBitmap(), bounds.x(), bounds.y(),
bounds.width(), bounds.height()),
@@ -257,11 +248,8 @@
class HSLImageSource : public gfx::ImageSkiaSource {
public:
- HSLImageSource(const ImageSkia& image,
- const color_utils::HSL& hsl_shift)
- : image_(image),
- hsl_shift_(hsl_shift) {
- }
+ HSLImageSource(const ImageSkia& image, const color_utils::HSL& hsl_shift)
+ : image_(image), hsl_shift_(hsl_shift) {}
HSLImageSource(const HSLImageSource&) = delete;
HSLImageSource& operator=(const HSLImageSource&) = delete;
@@ -286,16 +274,13 @@
// ImageSkiaSource which uses SkBitmapOperations::CreateButtonBackground
// to generate image reps for the target image. The image and mask can be
-// diferent sizes (crbug.com/171725).
-class ButtonImageSource: public gfx::ImageSkiaSource {
+// different sizes (crbug.com/171725).
+class ButtonImageSource : public gfx::ImageSkiaSource {
public:
ButtonImageSource(SkColor color,
const ImageSkia& image,
const ImageSkia& mask)
- : color_(color),
- image_(image),
- mask_(mask) {
- }
+ : color_(color), image_(image), mask_(mask) {}
ButtonImageSource(const ButtonImageSource&) = delete;
ButtonImageSource& operator=(const ButtonImageSource&) = delete;
@@ -329,13 +314,11 @@
// ImageSkiaSource which uses SkBitmap::extractSubset to generate image reps
// for the target image.
-class ExtractSubsetImageSource: public gfx::ImageSkiaSource {
+class ExtractSubsetImageSource : public gfx::ImageSkiaSource {
public:
ExtractSubsetImageSource(const gfx::ImageSkia& image,
const gfx::Rect& subset_bounds)
- : image_(image),
- subset_bounds_(subset_bounds) {
- }
+ : image_(image), subset_bounds_(subset_bounds) {}
ExtractSubsetImageSource(const ExtractSubsetImageSource&) = delete;
ExtractSubsetImageSource& operator=(const ExtractSubsetImageSource&) = delete;
@@ -348,8 +331,8 @@
if (image_rep.is_null())
return image_rep;
- SkIRect subset_bounds_in_pixel = RectToSkIRect(
- DIPToPixelBounds(subset_bounds_, image_rep.scale()));
+ SkIRect subset_bounds_in_pixel =
+ RectToSkIRect(DIPToPixelBounds(subset_bounds_, image_rep.scale()));
SkBitmap dst;
bool success =
image_rep.GetBitmap().extractSubset(&dst, subset_bounds_in_pixel);
@@ -371,8 +354,7 @@
const Size& target_dip_size)
: source_(source),
resize_method_(method),
- target_dip_size_(target_dip_size) {
- }
+ target_dip_size_(target_dip_size) {}
ResizeSource(const ResizeSource&) = delete;
ResizeSource& operator=(const ResizeSource&) = delete;
@@ -478,9 +460,7 @@
public:
RotatedSource(const ImageSkia& source,
SkBitmapOperations::RotationAmount rotation)
- : source_(source),
- rotation_(rotation) {
- }
+ : source_(source), rotation_(rotation) {}
RotatedSource(const RotatedSource&) = delete;
RotatedSource& operator=(const RotatedSource&) = delete;
@@ -588,6 +568,72 @@
const SkColor color_;
const gfx::ImageSkia image_;
};
+
+// Image source to create an image with a rounded rect background.
+class ImageWithRoundRectBackgroundSource : public gfx::CanvasImageSource {
+ public:
+ ImageWithRoundRectBackgroundSource(float size,
+ int radius,
+ SkColor color,
+ const gfx::ImageSkia& image)
+ : gfx::CanvasImageSource(gfx::Size(size, size)),
+ size_(size),
+ radius_(radius),
+ color_(color),
+ image_(image) {}
+
+ ImageWithRoundRectBackgroundSource(
+ const ImageWithRoundRectBackgroundSource&) = delete;
+ ImageWithRoundRectBackgroundSource& operator=(
+ const ImageWithRoundRectBackgroundSource&) = delete;
+
+ ~ImageWithRoundRectBackgroundSource() override = default;
+
+ // gfx::CanvasImageSource:
+ void Draw(gfx::Canvas* canvas) override {
+ cc::PaintFlags flags;
+ flags.setAntiAlias(true);
+ flags.setStyle(cc::PaintFlags::kFill_Style);
+ flags.setColor(color_);
+ canvas->DrawRoundRect(RectF{size_, size_}, radius_, flags);
+ // Center the image.
+ const int x = (size_ - image_.width()) / 2;
+ const int y = (size_ - image_.height()) / 2;
+ canvas->DrawImageInt(image_, x, y);
+ }
+
+ private:
+ const float size_;
+ const int radius_;
+ const SkColor color_;
+ const gfx::ImageSkia image_;
+};
+
+// Image source to create an image with a roundrect clip path.
+class ImageWithRoundRectClipSource : public gfx::CanvasImageSource {
+ public:
+ ImageWithRoundRectClipSource(int radius, const gfx::ImageSkia& image)
+ : gfx::CanvasImageSource(image.size()), radius_(radius), image_(image) {}
+
+ ImageWithRoundRectClipSource(const ImageWithRoundRectClipSource&) = delete;
+ ImageWithRoundRectClipSource& operator=(const ImageWithRoundRectClipSource&) =
+ delete;
+
+ ~ImageWithRoundRectClipSource() override = default;
+
+ // gfx::CanvasImageSource:
+ void Draw(gfx::Canvas* canvas) override {
+ canvas->ClipPath(
+ SkPath().addRoundRect(gfx::RectToSkRect(gfx::Rect(image_.size())),
+ radius_, radius_),
+ true);
+ canvas->DrawImageInt(image_, 0, 0);
+ }
+
+ private:
+ const int radius_;
+ const gfx::ImageSkia image_;
+};
} // namespace
// static
@@ -633,8 +679,10 @@
// static
ImageSkia ImageSkiaOperations::CreateTiledImage(const ImageSkia& source,
- int src_x, int src_y,
- int dst_w, int dst_h) {
+ int src_x,
+ int src_y,
+ int dst_w,
+ int dst_h) {
if (source.isNull())
return ImageSkia();
@@ -704,8 +752,7 @@
const gfx::Insets shadow_padding = -gfx::ShadowValue::GetMargin(shadows);
gfx::Size shadow_image_size = source.size();
- shadow_image_size.Enlarge(shadow_padding.width(),
- shadow_padding.height());
+ shadow_image_size.Enlarge(shadow_padding.width(), shadow_padding.height());
return ImageSkia(std::make_unique<DropShadowSource>(source, shadows),
shadow_image_size);
}
@@ -720,8 +767,8 @@
// static
ImageSkia ImageSkiaOperations::CreateRotatedImage(
- const ImageSkia& source,
- SkBitmapOperations::RotationAmount rotation) {
+ const ImageSkia& source,
+ SkBitmapOperations::RotationAmount rotation) {
if (source.isNull())
return ImageSkia();
@@ -763,4 +810,39 @@
return gfx::CanvasImageSource::MakeImageSkia<ImageWithCircleBackgroundSource>(
radius, color, image);
}
+
+ImageSkia ImageSkiaOperations::CreateImageWithRoundRectBackground(
+ float size,
+ int radius,
+ SkColor color,
+ const ImageSkia& image) {
+ DCHECK_GE(size, image.width());
+ DCHECK_GE(size, image.height());
+ return gfx::CanvasImageSource::MakeImageSkia<
+ ImageWithRoundRectBackgroundSource>(size, radius, color, image);
+}
+
+ImageSkia ImageSkiaOperations::CreateImageWithRoundRectClip(
+ int radius,
+ const ImageSkia& image) {
+ return gfx::CanvasImageSource::MakeImageSkia<ImageWithRoundRectClipSource>(
+ radius, image);
+}
+
+ImageSkia ImageSkiaOperations::CreateCroppedCenteredRoundRectImage(
+ const Size& size,
+ int border_radius,
+ const ImageSkia& image) {
+ float scale = std::min(static_cast<float>(image.width()) / size.width(),
+ static_cast<float>(image.height()) / size.height());
+ Size scaled_size = {base::ClampFloor(scale * size.width()),
+ base::ClampFloor(scale * size.height())};
+ Rect bounds{{0, 0}, image.size()};
+ bounds.ClampToCenteredSize(scaled_size);
+ auto scaled_and_cropped_image = CreateTiledImage(
+ image, bounds.x(), bounds.y(), bounds.width(), bounds.height());
+ auto resized_image = CreateResizedImage(
+ scaled_and_cropped_image, skia::ImageOperations::RESIZE_LANCZOS3, size);
+ return CreateImageWithRoundRectClip(border_radius, resized_image);
+}
} // namespace gfx
diff --git a/ui/gfx/image/image_skia_operations.h b/ui/gfx/image/image_skia_operations.h
index a25afd4..359a828 100644
--- a/ui/gfx/image/image_skia_operations.h
+++ b/ui/gfx/image/image_skia_operations.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -46,8 +46,10 @@
// because it tiles the original image, so your coordinates can extend
// outside the bounds of the original image.
static ImageSkia CreateTiledImage(const ImageSkia& image,
- int src_x, int src_y,
- int dst_w, int dst_h);
+ int src_x,
+ int src_y,
+ int dst_w,
+ int dst_h);
// Shift an image's HSL values. The shift values are in the range of 0-1,
// with the option to specify -1 for 'no change'. The shift values are
@@ -119,6 +121,24 @@
SkColor color,
const ImageSkia& image);
+ // Creates an image with a rounded rect background of the specified `size`,
+ // `color`, and `radius`.
+ static ImageSkia CreateImageWithRoundRectBackground(float size,
+ int radius,
+ SkColor color,
+ const ImageSkia& image);
+
+ // Creates an image with a roundrect clip path with `radius`.
+ static ImageSkia CreateImageWithRoundRectClip(int radius,
+ const ImageSkia& image);
+
+ // Returns an image of `size` that contains as much of `image` as possible
+ // without distorting the `image`. That result is clipped to a roundrect with
+ // radius `border_radius`.
+ static ImageSkia CreateCroppedCenteredRoundRectImage(const Size& size,
+ int border_radius,
+ const ImageSkia& image);
+
private:
ImageSkiaOperations(); // Class for scoping only.
};
diff --git a/ui/gfx/image/image_skia_operations_unittest.cc b/ui/gfx/image/image_skia_operations_unittest.cc
index 473e2d5..bb6acb1 100644
--- a/ui/gfx/image/image_skia_operations_unittest.cc
+++ b/ui/gfx/image/image_skia_operations_unittest.cc
@@ -1,11 +1,13 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/image/image_skia_operations.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
namespace gfx {
namespace {
diff --git a/ui/gfx/image/image_skia_rep.h b/ui/gfx/image/image_skia_rep.h
index 4f9d6b1..ab8535e 100644
--- a/ui/gfx/image/image_skia_rep.h
+++ b/ui/gfx/image/image_skia_rep.h
@@ -1,16 +1,17 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_IMAGE_IMAGE_SKIA_REP_H_
#define UI_GFX_IMAGE_IMAGE_SKIA_REP_H_
+#include "build/blink_buildflags.h"
#include "build/build_config.h"
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS) && !BUILDFLAG(USE_BLINK)
#include "ui/gfx/image/image_skia_rep_ios.h"
#else
#include "ui/gfx/image/image_skia_rep_default.h"
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
#endif // UI_GFX_IMAGE_IMAGE_SKIA_REP_H_
diff --git a/ui/gfx/image/image_skia_rep_default.cc b/ui/gfx/image/image_skia_rep_default.cc
index 66c7657..241a25a 100644
--- a/ui/gfx/image/image_skia_rep_default.cc
+++ b/ui/gfx/image/image_skia_rep_default.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -39,7 +39,7 @@
paint_image_ = cc::PaintImage::CreateFromBitmap(src);
}
-ImageSkiaRep::ImageSkiaRep(sk_sp<cc::PaintRecord> paint_record,
+ImageSkiaRep::ImageSkiaRep(cc::PaintRecord paint_record,
const gfx::Size& pixel_size,
float scale)
: paint_record_(std::move(paint_record)),
@@ -67,29 +67,18 @@
return static_cast<int>(pixel_height() / scale());
}
-sk_sp<cc::PaintRecord> ImageSkiaRep::GetPaintRecord() const {
+cc::PaintRecord ImageSkiaRep::GetPaintRecord() const {
DCHECK(type_ == ImageRepType::kImageTypeBitmap || !is_null());
// If this image rep is of |kImageTypeDrawable| then it must have a paint
// record.
if (type_ == ImageRepType::kImageTypeDrawable || paint_record_)
- return paint_record_;
+ return *paint_record_;
// If this ImageRep was generated using a bitmap then it may not have a
// paint record generated for it yet. We would have to generate it now.
- scoped_refptr<cc::DisplayItemList> display_item_list =
- base::MakeRefCounted<cc::DisplayItemList>(
- cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer);
-
- cc::RecordPaintCanvas record_canvas(
- display_item_list.get(), SkRect::MakeIWH(pixel_width(), pixel_height()));
-
- display_item_list->StartPaint();
+ cc::RecordPaintCanvas record_canvas;
record_canvas.drawImage(paint_image(), 0, 0);
- display_item_list->EndPaintOfPairedEnd();
- display_item_list->Finalize();
-
- paint_record_ = display_item_list->ReleaseAsRecord();
- return paint_record_;
+ return record_canvas.ReleaseAsRecord();
}
const SkBitmap& ImageSkiaRep::GetBitmap() const {
diff --git a/ui/gfx/image/image_skia_rep_default.h b/ui/gfx/image/image_skia_rep_default.h
index 651ff76..d2dd7cf 100644
--- a/ui/gfx/image/image_skia_rep_default.h
+++ b/ui/gfx/image/image_skia_rep_default.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -43,7 +43,7 @@
// is used when the image representation is sourced from a drawable such as
// CanvasImageSource. The `size` must not be empty; in that case the default
// constructor should be used instead.
- ImageSkiaRep(sk_sp<cc::PaintRecord> paint_record,
+ ImageSkiaRep(cc::PaintRecord paint_record,
const gfx::Size& size,
float scale);
@@ -75,7 +75,7 @@
// Returns the backing drawable as a PaintRecord. Use this when the type of
// ImageRep is |kImageTypeDrawable|.
- sk_sp<cc::PaintRecord> GetPaintRecord() const;
+ cc::PaintRecord GetPaintRecord() const;
const cc::PaintImage& paint_image() const { return paint_image_; }
bool has_paint_image() const { return !!paint_image_; }
@@ -89,7 +89,7 @@
// TODO(malaykeshav): Remove when migration is complete and it is safe.
cc::PaintImage paint_image_;
- mutable sk_sp<cc::PaintRecord> paint_record_;
+ mutable absl::optional<cc::PaintRecord> paint_record_;
ImageRepType type_;
Size pixel_size_;
diff --git a/ui/gfx/image/image_skia_rep_ios.cc b/ui/gfx/image/image_skia_rep_ios.cc
index 5fb5925..2de5b79 100644
--- a/ui/gfx/image/image_skia_rep_ios.cc
+++ b/ui/gfx/image/image_skia_rep_ios.cc
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/image_skia_rep_ios.h b/ui/gfx/image/image_skia_rep_ios.h
index 51e8f84..124aaae 100644
--- a/ui/gfx/image/image_skia_rep_ios.h
+++ b/ui/gfx/image/image_skia_rep_ios.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/image_skia_source.cc b/ui/gfx/image/image_skia_source.cc
index 53bc427..a9c4e75 100644
--- a/ui/gfx/image/image_skia_source.cc
+++ b/ui/gfx/image/image_skia_source.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/image_skia_source.h b/ui/gfx/image/image_skia_source.h
index 9ffc135..7858bc0 100644
--- a/ui/gfx/image/image_skia_source.h
+++ b/ui/gfx/image/image_skia_source.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/image_skia_unittest.cc b/ui/gfx/image/image_skia_unittest.cc
index 12b19b9..46e8eb0 100644
--- a/ui/gfx/image/image_skia_unittest.cc
+++ b/ui/gfx/image/image_skia_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,8 +8,8 @@
#include "base/check_op.h"
#include "base/command_line.h"
-#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "base/memory/raw_ptr.h"
#include "base/threading/simple_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -130,7 +130,7 @@
bool can_modify() const { return can_modify_; }
private:
- ImageSkia* image_skia_;
+ raw_ptr<ImageSkia> image_skia_;
bool can_read_;
bool can_modify_;
diff --git a/ui/gfx/image/image_skia_util_ios.h b/ui/gfx/image/image_skia_util_ios.h
index 6576ff8..b94c635 100644
--- a/ui/gfx/image/image_skia_util_ios.h
+++ b/ui/gfx/image/image_skia_util_ios.h
@@ -1,4 +1,4 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/image_skia_util_ios.mm b/ui/gfx/image/image_skia_util_ios.mm
index 4ecbfdc..0732567 100644
--- a/ui/gfx/image/image_skia_util_ios.mm
+++ b/ui/gfx/image/image_skia_util_ios.mm
@@ -1,4 +1,4 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,6 +10,7 @@
#include "skia/ext/skia_utils_ios.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
namespace gfx {
diff --git a/ui/gfx/image/image_skia_util_mac.h b/ui/gfx/image/image_skia_util_mac.h
index 5d7af20..1dff65e 100644
--- a/ui/gfx/image/image_skia_util_mac.h
+++ b/ui/gfx/image/image_skia_util_mac.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -27,7 +27,7 @@
GFX_EXPORT gfx::ImageSkia ImageSkiaFromResizedNSImage(NSImage* image,
NSSize size);
-// Converts to NSImage from ImageSkia.
+// Converts to NSImage from ImageSkia. Uses the sRGB color space.
GFX_EXPORT NSImage* NSImageFromImageSkia(const gfx::ImageSkia& image_skia);
// Converts to NSImage from given ImageSkia and a color space.
diff --git a/ui/gfx/image/image_skia_util_mac.mm b/ui/gfx/image/image_skia_util_mac.mm
index 35b3845..57cb0e4 100644
--- a/ui/gfx/image/image_skia_util_mac.mm
+++ b/ui/gfx/image/image_skia_util_mac.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -16,15 +16,16 @@
#include "skia/ext/skia_utils_mac.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
namespace {
-// Returns NSImageRep whose pixel size most closely matches |desired_size|.
+// Returns the NSImageRep whose pixel size most closely matches |desired_size|.
NSImageRep* GetNSImageRepWithPixelSize(NSImage* image,
NSSize desired_size) {
float smallest_diff = std::numeric_limits<float>::max();
NSImageRep* closest_match = nil;
- for (NSImageRep* image_rep in [image representations]) {
+ for (NSImageRep* image_rep in image.representations) {
float diff = std::abs(desired_size.width - [image_rep pixelsWide]) +
std::abs(desired_size.height - [image_rep pixelsHigh]);
if (diff < smallest_diff) {
@@ -35,9 +36,9 @@
return closest_match;
}
-// Returns true if NSImage has no representations
+// Returns true if the NSImage has no representations.
bool IsNSImageEmpty(NSImage* image) {
- return ([image representations].count == 0);
+ return image.representations.count == 0;
}
} // namespace
@@ -45,7 +46,7 @@
namespace gfx {
gfx::ImageSkia ImageSkiaFromNSImage(NSImage* image) {
- return ImageSkiaFromResizedNSImage(image, [image size]);
+ return ImageSkiaFromResizedNSImage(image, image.size);
}
gfx::ImageSkia ImageSkiaFromResizedNSImage(NSImage* image,
@@ -61,16 +62,15 @@
std::vector<float> supported_scales = ImageSkia::GetSupportedScales();
gfx::ImageSkia image_skia;
- for (size_t i = 0; i < supported_scales.size(); ++i) {
- float scale = supported_scales[i];
- NSSize desired_size_for_scale = NSMakeSize(desired_size.width * scale,
- desired_size.height * scale);
+ for (float scale : supported_scales) {
+ NSSize desired_size_for_scale =
+ NSMakeSize(desired_size.width * scale, desired_size.height * scale);
NSImageRep* ns_image_rep = GetNSImageRepWithPixelSize(image,
desired_size_for_scale);
- // TODO(dcheng): Should this function take a color space argument?
- SkBitmap bitmap(skia::NSImageRepToSkBitmapWithColorSpace(ns_image_rep,
- desired_size_for_scale, false, base::mac::GetGenericRGBColorSpace()));
+ SkBitmap bitmap(skia::NSImageRepToSkBitmapWithColorSpace(
+ ns_image_rep, desired_size_for_scale, false,
+ base::mac::GetSRGBColorSpace()));
if (bitmap.isNull())
continue;
@@ -80,19 +80,8 @@
}
NSImage* NSImageFromImageSkia(const gfx::ImageSkia& image_skia) {
- if (image_skia.isNull())
- return nil;
-
- base::scoped_nsobject<NSImage> image([[NSImage alloc] init]);
- image_skia.EnsureRepsForSupportedScales();
- std::vector<gfx::ImageSkiaRep> image_reps = image_skia.image_reps();
- for (std::vector<gfx::ImageSkiaRep>::const_iterator it = image_reps.begin();
- it != image_reps.end(); ++it) {
- [image addRepresentation:skia::SkBitmapToNSBitmapImageRep(it->GetBitmap())];
- }
-
- [image setSize:NSMakeSize(image_skia.width(), image_skia.height())];
- return [image.release() autorelease];
+ return NSImageFromImageSkiaWithColorSpace(image_skia,
+ base::mac::GetSRGBColorSpace());
}
NSImage* NSImageFromImageSkiaWithColorSpace(const gfx::ImageSkia& image_skia,
@@ -103,10 +92,9 @@
base::scoped_nsobject<NSImage> image([[NSImage alloc] init]);
image_skia.EnsureRepsForSupportedScales();
std::vector<gfx::ImageSkiaRep> image_reps = image_skia.image_reps();
- for (std::vector<gfx::ImageSkiaRep>::const_iterator it = image_reps.begin();
- it != image_reps.end(); ++it) {
+ for (const auto& rep : image_reps) {
[image addRepresentation:skia::SkBitmapToNSBitmapImageRepWithColorSpace(
- it->GetBitmap(), color_space)];
+ rep.GetBitmap(), color_space)];
}
[image setSize:NSMakeSize(image_skia.width(), image_skia.height())];
diff --git a/ui/gfx/image/image_unittest.cc b/ui/gfx/image/image_unittest.cc
index 94fea8b..64ba931 100644
--- a/ui/gfx/image/image_unittest.cc
+++ b/ui/gfx/image/image_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,33 +10,48 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkPaint.h"
+#include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_png_rep.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/image/image_unittest_util.h"
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "base/mac/foundation_util.h"
#include "skia/ext/skia_utils_ios.h"
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
+#include <CoreGraphics/CoreGraphics.h>
+
#include "base/mac/foundation_util.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
#include "skia/ext/skia_utils_mac.h"
#endif
namespace {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
const bool kUsesSkiaNatively = false;
#else
const bool kUsesSkiaNatively = true;
#endif
+#if BUILDFLAG(IS_MAC)
+bool IsSystemColorSpaceSRGB() {
+ CGColorSpaceRef color_space = base::mac::GetSystemColorSpace();
+ base::ScopedCFTypeRef<CFStringRef> name(CGColorSpaceCopyName(color_space));
+ return name &&
+ CFStringCompare(name, kCGColorSpaceSRGB, 0) == kCFCompareEqualTo;
+}
+#endif // BUILDFLAG(IS_MAC)
+
class ImageTest : public testing::Test {
public:
ImageTest() {
std::vector<float> scales;
scales.push_back(1.0f);
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
scales.push_back(2.0f);
#endif
gfx::ImageSkia::SetSupportedScales(scales);
@@ -56,7 +71,7 @@
// Test constructing a gfx::Image from an empty PlatformImage.
TEST_F(ImageTest, EmptyImageFromEmptyPlatformImage) {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
gfx::Image image1(nullptr);
EXPECT_TRUE(image1.IsEmpty());
EXPECT_EQ(0, image1.Width());
@@ -237,7 +252,7 @@
gt::MaxColorSpaceConversionColorShift()));
EXPECT_TRUE(gt::ImageSkiaStructureMatches(image_skia, kSize1x, kSize1x,
scales));
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
// IOS does not support arbitrary scale factors.
gfx::ImageSkiaRep rep_1_6x = image_skia.GetRepresentation(1.6f);
ASSERT_FALSE(rep_1_6x.is_null());
@@ -263,7 +278,7 @@
gfx::Image from_png(image_png_reps);
gfx::Image from_platform(gt::CopyViaPlatformType(from_png));
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// On iOS the platform type (UIImage) only supports one resolution.
std::vector<float> scales = gfx::ImageSkia::GetSupportedScales();
EXPECT_EQ(scales.size(), 1U);
@@ -281,7 +296,7 @@
EXPECT_TRUE(
gt::ArePNGBytesCloseToBitmap(*bytes1x, from_platform.AsBitmap(),
gt::MaxColorSpaceConversionColorShift()));
-#endif // defined(OS_IOS)
+#endif // BUILDFLAG(IS_IOS)
}
@@ -430,6 +445,13 @@
}
TEST_F(ImageTest, SkBitmapConversionPreservesOrientation) {
+#if BUILDFLAG(IS_MAC)
+ LOG_IF(WARNING, !IsSystemColorSpaceSRGB())
+ << "This test is designed to pass with the sRGB color space, which is "
+ "not set for your main display currently. Thus, colors can be off by "
+ "too big a margin, and the test can fail.";
+#endif // BUILDFLAG(IS_MAC)
+
const int width = 50;
const int height = 50;
SkBitmap bitmap;
diff --git a/ui/gfx/image/image_unittest_util.cc b/ui/gfx/image/image_unittest_util.cc
index 37f3b83..49988e9 100644
--- a/ui/gfx/image/image_unittest_util.cc
+++ b/ui/gfx/image/image_unittest_util.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -12,16 +12,19 @@
#include <cmath>
#include <memory>
+#include "base/memory/ref_counted_memory.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
+#include "ui/gfx/test/sk_color_eq.h"
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
#include "base/mac/scoped_cftyperef.h"
#include "skia/ext/skia_utils_ios.h"
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
#include "base/mac/mac_util.h"
#include "skia/ext/skia_utils_mac.h"
#endif
@@ -37,26 +40,6 @@
// error.
const int kMaxColorSpaceConversionColorShift = 40;
-bool ColorComponentsClose(SkColor component1,
- SkColor component2,
- int max_deviation) {
- int c1 = static_cast<int>(component1);
- int c2 = static_cast<int>(component2);
- return std::abs(c1 - c2) <= max_deviation;
-}
-
-bool ColorsClose(SkColor color1, SkColor color2, int max_deviation) {
- // Be tolerant of floating point rounding and lossy color space conversions.
- return ColorComponentsClose(SkColorGetR(color1), SkColorGetR(color2),
- max_deviation) &&
- ColorComponentsClose(SkColorGetG(color1), SkColorGetG(color2),
- max_deviation) &&
- ColorComponentsClose(SkColorGetB(color1), SkColorGetB(color2),
- max_deviation) &&
- ColorComponentsClose(SkColorGetA(color1), SkColorGetA(color2),
- max_deviation);
-}
-
} // namespace
std::vector<float> Get1xAnd2xScales() {
@@ -167,7 +150,8 @@
EXPECT_FALSE(bitmap.isNull());
EXPECT_LE(16, bitmap.width());
EXPECT_LE(16, bitmap.height());
- CheckColors(bitmap.getColor(10, 10), SK_ColorRED);
+ EXPECT_SKCOLOR_CLOSE(bitmap.getColor(10, 10), SK_ColorRED,
+ MaxColorSpaceConversionColorShift());
}
bool ImageSkiaStructureMatches(
@@ -204,7 +188,7 @@
PlatformImage CreatePlatformImage() {
SkBitmap bitmap(CreateBitmap(25, 25));
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
float scale = ImageSkia::GetMaxSupportedScale();
if (scale > 1.0) {
@@ -218,7 +202,7 @@
UIImage* image =
skia::SkBitmapToUIImageWithColorSpace(bitmap, scale, color_space);
return image;
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
NSImage* image = skia::SkBitmapToNSImageWithColorSpace(
bitmap, base::mac::GetGenericRGBColorSpace());
return image;
@@ -228,9 +212,9 @@
}
gfx::Image::RepresentationType GetPlatformRepresentationType() {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
return gfx::Image::kImageRepCocoaTouch;
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
return gfx::Image::kImageRepCocoa;
#else
return gfx::Image::kImageRepSkia;
@@ -238,9 +222,9 @@
}
PlatformImage ToPlatformType(const gfx::Image& image) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
return image.ToUIImage();
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
return image.ToNSImage();
#else
return image.AsImageSkia();
@@ -248,17 +232,17 @@
}
gfx::Image CopyViaPlatformType(const gfx::Image& image) {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
return gfx::Image(image.ToUIImage());
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
return gfx::Image(image.ToNSImage());
#else
return gfx::Image(image.AsImageSkia());
#endif
}
-#if defined(OS_APPLE)
-// Defined in image_unittest_util_mac.mm.
+#if BUILDFLAG(IS_APPLE)
+// Defined in image_unittest_util_apple.mm.
#else
SkColor GetPlatformImageColor(PlatformImage image, int x, int y) {
return image.bitmap()->getColor(x, y);
@@ -266,7 +250,8 @@
#endif
void CheckColors(SkColor color1, SkColor color2) {
- EXPECT_TRUE(ColorsClose(color1, color2, MaxColorSpaceConversionColorShift()));
+ // Be tolerant of floating point rounding and lossy color space conversions.
+ EXPECT_SKCOLOR_CLOSE(color1, color2, MaxColorSpaceConversionColorShift());
}
void CheckIsTransparent(SkColor color) {
@@ -274,7 +259,7 @@
}
bool IsPlatformImageValid(PlatformImage image) {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
return image != NULL;
#else
return !image.isNull();
@@ -282,7 +267,7 @@
}
bool PlatformImagesEqual(PlatformImage image1, PlatformImage image2) {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
return image1 == image2;
#else
return image1.BackedBySameObjectAs(image2);
diff --git a/ui/gfx/image/image_unittest_util.h b/ui/gfx/image/image_unittest_util.h
index 51e5a52..d9e9606 100644
--- a/ui/gfx/image/image_unittest_util.h
+++ b/ui/gfx/image/image_unittest_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -18,9 +18,9 @@
namespace gfx {
namespace test {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
typedef UIImage* PlatformImage;
-#elif defined(OS_MAC)
+#elif BUILDFLAG(IS_MAC)
typedef NSImage* PlatformImage;
#else
typedef gfx::ImageSkia PlatformImage;
diff --git a/ui/gfx/image/image_unittest_util_apple.mm b/ui/gfx/image/image_unittest_util_apple.mm
new file mode 100644
index 0000000..4e3c07c
--- /dev/null
+++ b/ui/gfx/image/image_unittest_util_apple.mm
@@ -0,0 +1,58 @@
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/image/image_unittest_util.h"
+
+#import <CoreGraphics/CoreGraphics.h>
+
+#include "base/bit_cast.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "build/build_config.h"
+
+#if BUILDFLAG(IS_MAC)
+#import <AppKit/AppKit.h>
+#elif BUILDFLAG(IS_IOS)
+#import <UIKit/UIKit.h>
+#endif
+
+namespace gfx::test {
+
+// The |x| and |y| coordinates are interpreted as scale-independent on the Mac
+// and on iOS.
+SkColor GetPlatformImageColor(PlatformImage image, int x, int y) {
+#if BUILDFLAG(IS_MAC)
+ CGImageRef image_ref = [image CGImageForProposedRect:nil
+ context:nil
+ hints:nil];
+ CGRect target_pixel =
+ CGRectMake(x * CGImageGetWidth(image_ref) / image.size.width,
+ y * CGImageGetHeight(image_ref) / image.size.height, 1, 1);
+#elif BUILDFLAG(IS_IOS)
+ CGImageRef image_ref = image.CGImage;
+ CGRect target_pixel = CGRectMake(x * image.scale, y * image.scale, 1, 1);
+#endif
+
+ // Start by extracting the target pixel into a 1x1 CGImage.
+ base::ScopedCFTypeRef<CGImageRef> pixel_image(CGImageCreateWithImageInRect(
+ image_ref, target_pixel));
+
+ // Draw that pixel into a 1x1 bitmap context.
+ base::ScopedCFTypeRef<CGColorSpaceRef> color_space(
+ CGColorSpaceCreateDeviceRGB());
+ base::ScopedCFTypeRef<CGContextRef> bitmap_context(CGBitmapContextCreate(
+ /*data=*/nullptr,
+ /*width=*/1,
+ /*height=*/1,
+ /*bitsPerComponent=*/8,
+ /*bytesPerRow=*/4, color_space,
+ kCGImageAlphaPremultipliedFirst |
+ static_cast<CGImageAlphaInfo>(kCGBitmapByteOrder32Host)));
+ CGContextDrawImage(bitmap_context, CGRectMake(0, 0, 1, 1), pixel_image);
+
+ // The CGBitmapContext has the same memory layout as SkColor, so we can just
+ // read an SkColor straight out of the context.
+ return *reinterpret_cast<SkColor*>(CGBitmapContextGetData(bitmap_context));
+}
+
+} // namespace gfx::test
diff --git a/ui/gfx/image/image_unittest_util_ios.mm b/ui/gfx/image/image_unittest_util_ios.mm
deleted file mode 100644
index ba55030..0000000
--- a/ui/gfx/image/image_unittest_util_ios.mm
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <CoreGraphics/CoreGraphics.h>
-#import <UIKit/UIKit.h>
-
-#include "base/mac/scoped_cftyperef.h"
-#include "skia/ext/skia_utils_ios.h"
-#include "ui/gfx/image/image_unittest_util.h"
-
-namespace gfx {
-namespace test {
-
-// The |x| and |y| coordinates are interpreted as scale-independent in ios.
-SkColor GetPlatformImageColor(PlatformImage image, int x, int y) {
- // Start by extracting the target pixel into a 1x1 CGImage.
- base::ScopedCFTypeRef<CGImageRef> pixel_image(CGImageCreateWithImageInRect(
- image.CGImage, CGRectMake(x * image.scale, y * image.scale, 1, 1)));
-
- // Draw that pixel into a 1x1 bitmap context.
- base::ScopedCFTypeRef<CGColorSpaceRef> color_space(
- CGColorSpaceCreateDeviceRGB());
- base::ScopedCFTypeRef<CGContextRef> bitmap_context(CGBitmapContextCreate(
- /*data=*/ NULL,
- /*width=*/ 1,
- /*height=*/ 1,
- /*bitsPerComponent=*/ 8,
- /*bytesPerRow=*/ 4,
- color_space,
- kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host));
- CGContextDrawImage(bitmap_context, CGRectMake(0, 0, 1, 1), pixel_image);
-
- // The CGBitmapContext has the same memory layout as SkColor, so we can just
- // read an SkColor straight out of the context.
- SkColor* data =
- reinterpret_cast<SkColor*>(CGBitmapContextGetData(bitmap_context));
- return *data;
-}
-
-} // namespace test
-} // namespace gfx
diff --git a/ui/gfx/image/image_unittest_util_mac.mm b/ui/gfx/image/image_unittest_util_mac.mm
deleted file mode 100644
index 99aaf6a..0000000
--- a/ui/gfx/image/image_unittest_util_mac.mm
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <AppKit/AppKit.h>
-
-#include "skia/ext/skia_utils_mac.h"
-#include "ui/gfx/image/image_unittest_util.h"
-
-namespace gfx {
-namespace test {
-
-SkColor GetPlatformImageColor(PlatformImage image, int x, int y) {
- // AppKit's coordinate system is flipped.
- y = [image size].height - y;
-
- [image lockFocus];
- NSColor* color = NSReadPixel(NSMakePoint(x, y));
- [image unlockFocus];
- return skia::NSDeviceColorToSkColor(
- [color colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]]);
-}
-
-} // namespace test
-} // namespace gfx
diff --git a/ui/gfx/image/image_util.cc b/ui/gfx/image/image_util.cc
index ce94c77..1dd32dd 100644
--- a/ui/gfx/image/image_util.cc
+++ b/ui/gfx/image/image_util.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,7 +9,6 @@
#include <algorithm>
#include <memory>
-#include "base/cxx17_backports.h"
#include "build/build_config.h"
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -17,6 +16,7 @@
#include "ui/gfx/codec/webp_codec.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/image/resize_image_dimensions.h"
namespace {
@@ -38,7 +38,7 @@
namespace gfx {
// The iOS implementations of the JPEG functions are in image_util_ios.mm.
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
Image ImageFrom1xJPEGEncodedData(const unsigned char* input,
size_t input_size) {
@@ -62,13 +62,13 @@
}
// The MacOS implementation of this function is in image_utils_mac.mm.
-#if !defined(OS_MAC)
+#if !BUILDFLAG(IS_MAC)
bool JPEG1xEncodedDataFromImage(const Image& image,
int quality,
std::vector<unsigned char>* dst) {
return JPEG1xEncodedDataFromSkiaRepresentation(image, quality, dst);
}
-#endif // !defined(OS_MAC)
+#endif // !BUILDFLAG(IS_MAC)
bool JPEG1xEncodedDataFromSkiaRepresentation(const Image& image,
int quality,
@@ -112,8 +112,8 @@
(bitmap.width() > max_width || bitmap.height() > max_height)) {
double scale = std::min(static_cast<double>(max_width) / bitmap.width(),
static_cast<double>(max_height) / bitmap.height());
- int width = base::clamp<int>(scale * bitmap.width(), 1, max_width);
- int height = base::clamp<int>(scale * bitmap.height(), 1, max_height);
+ int width = std::clamp<int>(scale * bitmap.width(), 1, max_width);
+ int height = std::clamp<int>(scale * bitmap.height(), 1, max_height);
SkBitmap new_bitmap = skia::ImageOperations::Resize(
bitmap, skia::ImageOperations::RESIZE_GOOD, width, height);
return Image(ImageSkia(ImageSkiaRep(new_bitmap, 0.0f)));
@@ -121,7 +121,7 @@
return image;
}
-#endif // !defined(OS_IOS)
+#endif // !BUILDFLAG(IS_IOS)
void GetVisibleMargins(const ImageSkia& image, int* left, int* right) {
*left = 0;
diff --git a/ui/gfx/image/image_util.h b/ui/gfx/image/image_util.h
index aa954a2..7ac58e0 100644
--- a/ui/gfx/image/image_util.h
+++ b/ui/gfx/image/image_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/image_util_ios.mm b/ui/gfx/image/image_util_ios.mm
index 81ac792..6fcdb5f 100644
--- a/ui/gfx/image/image_util_ios.mm
+++ b/ui/gfx/image/image_util_ios.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/image_util_mac.mm b/ui/gfx/image/image_util_mac.mm
index 5be20b0..c4dbfe0 100644
--- a/ui/gfx/image/image_util_mac.mm
+++ b/ui/gfx/image/image_util_mac.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -26,8 +26,8 @@
float compressionFactor = quality / 100.0;
NSDictionary* options = @{ NSImageCompressionFactor : @(compressionFactor)};
- NSData* data =
- [rep representationUsingType:NSJPEGFileType properties:options];
+ NSData* data = [rep representationUsingType:NSBitmapImageFileTypeJPEG
+ properties:options];
if ([data length] == 0)
return false;
diff --git a/ui/gfx/image/image_util_unittest.cc b/ui/gfx/image/image_util_unittest.cc
index 0ef65fd..6c7056a 100644
--- a/ui/gfx/image/image_util_unittest.cc
+++ b/ui/gfx/image/image_util_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/mojom/BUILD.gn b/ui/gfx/image/mojom/BUILD.gn
index dd07e3c..e174c49 100644
--- a/ui/gfx/image/mojom/BUILD.gn
+++ b/ui/gfx/image/mojom/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
+# Copyright 2017 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -7,6 +7,14 @@
mojom("mojom") {
sources = [ "image.mojom" ]
+ webui_module_path = "chrome://resources/mojo/ui/gfx/image/mojom"
+
+ # Generate WebUI bindings in TypeScript.
+ use_typescript_sources = true
+
+ # Used by content/common so need legacy JS bindings for Blink.
+ generate_legacy_js_bindings = true
+
public_deps = [ "//skia/public/mojom" ]
cpp_typemaps = [
diff --git a/ui/gfx/image/mojom/image.mojom b/ui/gfx/image/mojom/image.mojom
index e875200..d2b712d 100644
--- a/ui/gfx/image/mojom/image.mojom
+++ b/ui/gfx/image/mojom/image.mojom
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/mojom/image_skia_mojom_traits.cc b/ui/gfx/image/mojom/image_skia_mojom_traits.cc
index cda3a62..bc1457c 100644
--- a/ui/gfx/image/mojom/image_skia_mojom_traits.cc
+++ b/ui/gfx/image/mojom/image_skia_mojom_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/mojom/image_skia_mojom_traits.h b/ui/gfx/image/mojom/image_skia_mojom_traits.h
index 701b563..a0733b4 100644
--- a/ui/gfx/image/mojom/image_skia_mojom_traits.h
+++ b/ui/gfx/image/mojom/image_skia_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/mojom/image_traits_test_service.mojom b/ui/gfx/image/mojom/image_traits_test_service.mojom
index 72ab4b6..d098641 100644
--- a/ui/gfx/image/mojom/image_traits_test_service.mojom
+++ b/ui/gfx/image/mojom/image_traits_test_service.mojom
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/image/mojom/image_traits_unittest.cc b/ui/gfx/image/mojom/image_traits_unittest.cc
index 297a929..281d235 100644
--- a/ui/gfx/image/mojom/image_traits_unittest.cc
+++ b/ui/gfx/image/mojom/image_traits_unittest.cc
@@ -1,11 +1,10 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <utility>
#include <vector>
-#include "base/macros.h"
#include "base/test/task_environment.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h"
diff --git a/ui/gfx/image/resize_image_dimensions.h b/ui/gfx/image/resize_image_dimensions.h
index 65f7925..39c0338 100644
--- a/ui/gfx/image/resize_image_dimensions.h
+++ b/ui/gfx/image/resize_image_dimensions.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/interpolated_transform.cc b/ui/gfx/interpolated_transform.cc
index 6277fa4..88da97f 100644
--- a/ui/gfx/interpolated_transform.cc
+++ b/ui/gfx/interpolated_transform.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,6 +9,7 @@
#include "base/check.h"
#include "base/numerics/safe_conversions.h"
#include "ui/gfx/animation/tween.h"
+#include "ui/gfx/geometry/transform_util.h"
namespace {
@@ -29,8 +30,6 @@
if (!IsMultipleOfNinetyDegrees(degrees) || !rotation)
return false;
- gfx::Transform transform;
- skia::Matrix44& m = transform.matrix();
float degrees_by_ninety = degrees / 90.0f;
int n = base::ClampRound(degrees_by_ninety);
@@ -40,21 +39,15 @@
n += 4;
// n should now be in the range [0, 3]
- if (n == 1) {
- m.set3x3( 0, 1, 0,
- -1, 0, 0,
- 0, 0, 1);
+ if (n == 0) {
+ rotation->MakeIdentity();
+ } else if (n == 1) {
+ *rotation = gfx::Transform::Make90degRotation();
} else if (n == 2) {
- m.set3x3(-1, 0, 0,
- 0, -1, 0,
- 0, 0, 1);
+ *rotation = gfx::Transform::Make180degRotation();
} else if (n == 3) {
- m.set3x3( 0, -1, 0,
- 1, 0, 0,
- 0, 0, 1);
+ *rotation = gfx::Transform::Make270degRotation();
}
-
- *rotation = transform;
return true;
}
@@ -86,7 +79,7 @@
t = 1.0f - t;
gfx::Transform result = InterpolateButDoNotCompose(t);
if (child_.get()) {
- result.ConcatTransform(child_->Interpolate(t));
+ result.PostConcat(child_->Interpolate(t));
}
return result;
}
@@ -359,15 +352,14 @@
InterpolatedMatrixTransform::InterpolateButDoNotCompose(float t) const {
gfx::DecomposedTransform blended =
gfx::BlendDecomposedTransforms(end_decomp_, start_decomp_, t);
- return gfx::ComposeTransform(blended);
+ return gfx::Transform::Compose(blended);
}
void InterpolatedMatrixTransform::Init(const gfx::Transform& start_transform,
const gfx::Transform& end_transform) {
- bool success = gfx::DecomposeTransform(&start_decomp_, start_transform);
- DCHECK(success);
- success = gfx::DecomposeTransform(&end_decomp_, end_transform);
- DCHECK(success);
+ // Both transforms should be decomposible.
+ start_decomp_ = *start_transform.Decompose();
+ end_decomp_ = *end_transform.Decompose();
}
} // namespace ui
diff --git a/ui/gfx/interpolated_transform.h b/ui/gfx/interpolated_transform.h
index b836e24..d85293e 100644
--- a/ui/gfx/interpolated_transform.h
+++ b/ui/gfx/interpolated_transform.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,11 +7,10 @@
#include <memory>
-#include "base/macros.h"
+#include "ui/gfx/geometry/decomposed_transform.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/point3_f.h"
#include "ui/gfx/geometry/transform.h"
-#include "ui/gfx/geometry/transform_util.h"
#include "ui/gfx/geometry/vector3d_f.h"
#include "ui/gfx/gfx_export.h"
diff --git a/ui/gfx/interpolated_transform_unittest.cc b/ui/gfx/interpolated_transform_unittest.cc
index 3de686d..0c98cea 100644
--- a/ui/gfx/interpolated_transform_unittest.cc
+++ b/ui/gfx/interpolated_transform_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,19 +6,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
-
-namespace {
-
-void CheckApproximatelyEqual(const gfx::Transform& lhs,
- const gfx::Transform& rhs) {
- for (int i = 0; i < 4; ++i) {
- for (int j = 0; j < 4; ++j) {
- EXPECT_FLOAT_EQ(lhs.matrix().get(i, j), rhs.matrix().get(i, j));
- }
- }
-}
-
-} // namespace
+#include "ui/gfx/geometry/test/geometry_util.h"
TEST(InterpolatedTransformTest, InterpolatedRotation) {
ui::InterpolatedRotation interpolated_rotation(0, 100);
@@ -29,9 +17,9 @@
gfx::Transform rotation;
rotation.Rotate(i);
gfx::Transform interpolated = interpolated_rotation.Interpolate(i / 100.0f);
- CheckApproximatelyEqual(rotation, interpolated);
+ EXPECT_TRANSFORM_EQ(rotation, interpolated);
interpolated = interpolated_rotation_diff_start_end.Interpolate(i + 100);
- CheckApproximatelyEqual(rotation, interpolated);
+ EXPECT_TRANSFORM_EQ(rotation, interpolated);
}
}
@@ -45,9 +33,9 @@
gfx::Transform scale;
scale.Scale3d(i, i, i);
gfx::Transform interpolated = interpolated_scale.Interpolate(i / 100.0f);
- CheckApproximatelyEqual(scale, interpolated);
+ EXPECT_TRANSFORM_EQ(scale, interpolated);
interpolated = interpolated_scale_diff_start_end.Interpolate(i + 100);
- CheckApproximatelyEqual(scale, interpolated);
+ EXPECT_TRANSFORM_EQ(scale, interpolated);
}
}
@@ -62,9 +50,9 @@
gfx::Transform xform;
xform.Translate(i, i);
gfx::Transform interpolated = interpolated_xform.Interpolate(i / 100.0f);
- CheckApproximatelyEqual(xform, interpolated);
+ EXPECT_TRANSFORM_EQ(xform, interpolated);
interpolated = interpolated_xform_diff_start_end.Interpolate(i + 100);
- CheckApproximatelyEqual(xform, interpolated);
+ EXPECT_TRANSFORM_EQ(xform, interpolated);
}
}
@@ -79,9 +67,9 @@
gfx::Transform xform;
xform.Translate3d(i, i, i);
gfx::Transform interpolated = interpolated_xform.Interpolate(i / 100.0f);
- CheckApproximatelyEqual(xform, interpolated);
+ EXPECT_TRANSFORM_EQ(xform, interpolated);
interpolated = interpolated_xform_diff_start_end.Interpolate(i + 100);
- CheckApproximatelyEqual(xform, interpolated);
+ EXPECT_TRANSFORM_EQ(xform, interpolated);
}
}
@@ -92,13 +80,13 @@
ui::InterpolatedTransformAboutPivot interpolated_xform(
pivot, std::make_unique<ui::InterpolatedRotation>(0, 90));
gfx::Transform result = interpolated_xform.Interpolate(0.0f);
- CheckApproximatelyEqual(gfx::Transform(), result);
+ EXPECT_TRANSFORM_EQ(gfx::Transform(), result);
result = interpolated_xform.Interpolate(1.0f);
gfx::Point expected_result = pivot;
- result.TransformPoint(&pivot);
+ pivot = result.MapPoint(pivot);
EXPECT_EQ(expected_result, pivot);
expected_result = gfx::Point(0, 100);
- result.TransformPoint(&above_pivot);
+ above_pivot = result.MapPoint(above_pivot);
EXPECT_EQ(expected_result, above_pivot);
}
@@ -109,13 +97,13 @@
pivot, std::make_unique<ui::InterpolatedScale>(gfx::Point3F(1, 1, 1),
gfx::Point3F(2, 2, 2)));
gfx::Transform result = interpolated_xform.Interpolate(0.0f);
- CheckApproximatelyEqual(gfx::Transform(), result);
+ EXPECT_TRANSFORM_EQ(gfx::Transform(), result);
result = interpolated_xform.Interpolate(1.0f);
gfx::Point expected_result = pivot;
- result.TransformPoint(&pivot);
+ pivot = result.MapPoint(pivot);
EXPECT_EQ(expected_result, pivot);
expected_result = gfx::Point(100, 300);
- result.TransformPoint(&above_pivot);
+ above_pivot = result.MapPoint(above_pivot);
EXPECT_EQ(expected_result, above_pivot);
}
@@ -176,11 +164,10 @@
std::unique_ptr<ui::InterpolatedTransform> screen_rotation(
GetScreenRotation(degrees, reversed));
gfx::Transform interpolated = screen_rotation->Interpolate(1.0f);
- skia::Matrix44& m = interpolated.matrix();
// Upper-left 3x3 matrix should all be 0, 1 or -1.
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 3; ++col) {
- float entry = m.get(row, col);
+ float entry = interpolated.rc(row, col);
EXPECT_TRUE(entry == 0 || entry == 1 || entry == -1);
}
}
@@ -226,11 +213,10 @@
TEST(InterpolatedTransformTest, MaximizeEndsCleanly) {
std::unique_ptr<ui::InterpolatedTransform> maximize(GetMaximize());
gfx::Transform interpolated = maximize->Interpolate(1.0f);
- skia::Matrix44& m = interpolated.matrix();
// Upper-left 3x3 matrix should all be 0, 1 or -1.
for (int row = 0; row < 3; ++row) {
for (int col = 0; col < 3; ++col) {
- float entry = m.get(row, col);
+ float entry = interpolated.rc(row, col);
EXPECT_TRUE(entry == 0 || entry == 1 || entry == -1);
}
}
diff --git a/ui/gfx/ios/BUILD.gn b/ui/gfx/ios/BUILD.gn
new file mode 100644
index 0000000..ebec985
--- /dev/null
+++ b/ui/gfx/ios/BUILD.gn
@@ -0,0 +1,11 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("uikit_util") {
+ sources = [
+ "uikit_util.h",
+ "uikit_util.mm",
+ ]
+ frameworks = [ "UIKit.framework" ]
+}
diff --git a/ui/gfx/ios/NSString+CrStringDrawing.h b/ui/gfx/ios/NSString+CrStringDrawing.h
index d7c6c49..83eb8f2 100644
--- a/ui/gfx/ios/NSString+CrStringDrawing.h
+++ b/ui/gfx/ios/NSString+CrStringDrawing.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ios/NSString+CrStringDrawing.mm b/ui/gfx/ios/NSString+CrStringDrawing.mm
index f482ea1..570147a 100644
--- a/ui/gfx/ios/NSString+CrStringDrawing.mm
+++ b/ui/gfx/ios/NSString+CrStringDrawing.mm
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ios/NSString+CrStringDrawing_unittest.mm b/ui/gfx/ios/NSString+CrStringDrawing_unittest.mm
index b33a895..2e681ba 100644
--- a/ui/gfx/ios/NSString+CrStringDrawing_unittest.mm
+++ b/ui/gfx/ios/NSString+CrStringDrawing_unittest.mm
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ui/gfx/ios/NSString+CrStringDrawing.h"
diff --git a/ui/gfx/ios/uikit_util.h b/ui/gfx/ios/uikit_util.h
index fbacda3..2d6f5a5 100644
--- a/ui/gfx/ios/uikit_util.h
+++ b/ui/gfx/ios/uikit_util.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,19 +7,17 @@
#import <UIKit/UIKit.h>
-#include "base/compiler_specific.h"
-
// UI Util containing functions that require UIKit.
namespace ui {
// Returns the closest pixel-aligned value higher than |value|, taking the scale
// factor into account. At a scale of 1, equivalent to ceil().
-CGFloat AlignValueToUpperPixel(CGFloat value) WARN_UNUSED_RESULT;
+[[nodiscard]] CGFloat AlignValueToUpperPixel(CGFloat value);
// Returns the size resulting from applying AlignToUpperPixel to both
// components.
-CGSize AlignSizeToUpperPixel(CGSize size) WARN_UNUSED_RESULT;
+[[nodiscard]] CGSize AlignSizeToUpperPixel(CGSize size);
} // namespace ui
diff --git a/ui/gfx/ios/uikit_util.mm b/ui/gfx/ios/uikit_util.mm
index 2e0bfdb..d73b0ce 100644
--- a/ui/gfx/ios/uikit_util.mm
+++ b/ui/gfx/ios/uikit_util.mm
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ios/uikit_util_unittest.mm b/ui/gfx/ios/uikit_util_unittest.mm
index 269b4b3..a3df27c 100644
--- a/ui/gfx/ios/uikit_util_unittest.mm
+++ b/ui/gfx/ios/uikit_util_unittest.mm
@@ -1,13 +1,13 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#import "ui/gfx/ios/uikit_util.h"
+
#import <Foundation/Foundation.h>
#include <stddef.h>
-#include "base/cxx17_backports.h"
#include "testing/platform_test.h"
-#import "ui/gfx/ios/uikit_util.h"
namespace {
@@ -20,7 +20,7 @@
// "integer" values within <1 of the original value in the scaled space.
CGFloat test_values[] = { 10.0, 55.5, 3.1, 2.9 };
const CGFloat kMaxAlignDelta = 0.9999;
- size_t value_count = base::size(test_values);
+ size_t value_count = std::size(test_values);
for (unsigned int i = 0; i < value_count; ++i) {
CGFloat aligned = ui::AlignValueToUpperPixel(test_values[i]);
EXPECT_FLOAT_EQ(aligned * scale, floor(aligned * scale));
@@ -35,7 +35,7 @@
// "integer" values within <1 of the original value in the scaled space.
CGFloat test_values[] = { 10.0, 55.5, 3.1, 2.9 };
const CGFloat kMaxAlignDelta = 0.9999;
- size_t value_count = base::size(test_values);
+ size_t value_count = std::size(test_values);
for (unsigned int i = 0; i < value_count; ++i) {
CGFloat width = test_values[i];
CGFloat height = test_values[(i + 1) % value_count];
diff --git a/ui/gfx/ipc/BUILD.gn b/ui/gfx/ipc/BUILD.gn
index 9767b92..83f5cd0 100644
--- a/ui/gfx/ipc/BUILD.gn
+++ b/ui/gfx/ipc/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/ui/gfx/ipc/buffer_types/BUILD.gn b/ui/gfx/ipc/buffer_types/BUILD.gn
index 3cf5eca..550b4f0 100644
--- a/ui/gfx/ipc/buffer_types/BUILD.gn
+++ b/ui/gfx/ipc/buffer_types/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2018 The Chromium Authors. All rights reserved.
+# Copyright 2018 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/ui/gfx/ipc/buffer_types/gfx_ipc_export.h b/ui/gfx/ipc/buffer_types/gfx_ipc_export.h
index 83a48df..ba99e9f 100644
--- a/ui/gfx/ipc/buffer_types/gfx_ipc_export.h
+++ b/ui/gfx/ipc/buffer_types/gfx_ipc_export.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ipc/buffer_types/gfx_param_traits.cc b/ui/gfx/ipc/buffer_types/gfx_param_traits.cc
index 507b1e7..a73ff05 100644
--- a/ui/gfx/ipc/buffer_types/gfx_param_traits.cc
+++ b/ui/gfx/ipc/buffer_types/gfx_param_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,6 +9,7 @@
#include <string>
+#include "base/numerics/safe_conversions.h"
#include "base/strings/stringprintf.h"
namespace IPC {
@@ -32,7 +33,8 @@
void ParamTraits<gfx::BufferUsageAndFormat>::Log(
const gfx::BufferUsageAndFormat& p,
std::string* l) {
- l->append(base::StringPrintf("(%d, %d)", p.usage, p.format));
+ l->append(base::StringPrintf("(%d, %u)", p.usage,
+ base::strict_cast<uint32_t>(p.format)));
}
} // namespace IPC
diff --git a/ui/gfx/ipc/buffer_types/gfx_param_traits.h b/ui/gfx/ipc/buffer_types/gfx_param_traits.h
index 6bef3e5..2786d4f 100644
--- a/ui/gfx/ipc/buffer_types/gfx_param_traits.h
+++ b/ui/gfx/ipc/buffer_types/gfx_param_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ipc/buffer_types/gfx_param_traits_macros.h b/ui/gfx/ipc/buffer_types/gfx_param_traits_macros.h
index 502a4f1..d262d25 100644
--- a/ui/gfx/ipc/buffer_types/gfx_param_traits_macros.h
+++ b/ui/gfx/ipc/buffer_types/gfx_param_traits_macros.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ipc/color/BUILD.gn b/ui/gfx/ipc/color/BUILD.gn
index a9ab032..38a0694 100644
--- a/ui/gfx/ipc/color/BUILD.gn
+++ b/ui/gfx/ipc/color/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
+# Copyright 2016 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/ui/gfx/ipc/color/gfx_ipc_color_export.h b/ui/gfx/ipc/color/gfx_ipc_color_export.h
index eae168d..4ba0e11 100644
--- a/ui/gfx/ipc/color/gfx_ipc_color_export.h
+++ b/ui/gfx/ipc/color/gfx_ipc_color_export.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ipc/color/gfx_param_traits.cc b/ui/gfx/ipc/color/gfx_param_traits.cc
index 2e9b2b5..3b49915 100644
--- a/ui/gfx/ipc/color/gfx_param_traits.cc
+++ b/ui/gfx/ipc/color/gfx_param_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -51,7 +51,8 @@
const gfx::DisplayColorSpaces& p) {
WriteParam(m, p.color_spaces_);
WriteParam(m, p.buffer_formats_);
- WriteParam(m, p.sdr_white_level_);
+ WriteParam(m, p.sdr_max_luminance_nits_);
+ WriteParam(m, p.hdr_max_luminance_relative_);
}
bool ParamTraits<gfx::DisplayColorSpaces>::Read(const base::Pickle* m,
@@ -61,7 +62,9 @@
return false;
if (!ReadParam(m, iter, &r->buffer_formats_))
return false;
- if (!ReadParam(m, iter, &r->sdr_white_level_))
+ if (!ReadParam(m, iter, &r->sdr_max_luminance_nits_))
+ return false;
+ if (!ReadParam(m, iter, &r->hdr_max_luminance_relative_))
return false;
return true;
}
diff --git a/ui/gfx/ipc/color/gfx_param_traits.h b/ui/gfx/ipc/color/gfx_param_traits.h
index 8969194..b98cac0 100644
--- a/ui/gfx/ipc/color/gfx_param_traits.h
+++ b/ui/gfx/ipc/color/gfx_param_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ipc/color/gfx_param_traits_macros.h b/ui/gfx/ipc/color/gfx_param_traits_macros.h
index bd05adb..4b6514f 100644
--- a/ui/gfx/ipc/color/gfx_param_traits_macros.h
+++ b/ui/gfx/ipc/color/gfx_param_traits_macros.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ipc/geometry/BUILD.gn b/ui/gfx/ipc/geometry/BUILD.gn
index b8796b2..4d0a150 100644
--- a/ui/gfx/ipc/geometry/BUILD.gn
+++ b/ui/gfx/ipc/geometry/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/ui/gfx/ipc/geometry/gfx_ipc_geometry_export.h b/ui/gfx/ipc/geometry/gfx_ipc_geometry_export.h
index 32a07cd..912a3b1 100644
--- a/ui/gfx/ipc/geometry/gfx_ipc_geometry_export.h
+++ b/ui/gfx/ipc/geometry/gfx_ipc_geometry_export.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ipc/geometry/gfx_param_traits.cc b/ui/gfx/ipc/geometry/gfx_param_traits.cc
index 20bc0882..3f95359 100644
--- a/ui/gfx/ipc/geometry/gfx_param_traits.cc
+++ b/ui/gfx/ipc/geometry/gfx_param_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ipc/geometry/gfx_param_traits.h b/ui/gfx/ipc/geometry/gfx_param_traits.h
index 3020a09..4329f7c 100644
--- a/ui/gfx/ipc/geometry/gfx_param_traits.h
+++ b/ui/gfx/ipc/geometry/gfx_param_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ipc/gfx_ipc_export.h b/ui/gfx/ipc/gfx_ipc_export.h
index 0362b5b..6cd3002 100644
--- a/ui/gfx/ipc/gfx_ipc_export.h
+++ b/ui/gfx/ipc/gfx_ipc_export.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ipc/gfx_param_traits.cc b/ui/gfx/ipc/gfx_param_traits.cc
index 49e2135..c64fba0 100644
--- a/ui/gfx/ipc/gfx_param_traits.cc
+++ b/ui/gfx/ipc/gfx_param_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,19 +9,21 @@
#include <string>
+#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
+#include "build/build_config.h"
#include "ui/gfx/ipc/geometry/gfx_param_traits.h"
#include "ui/gfx/range/range.h"
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "ipc/mach_port_mac.h"
#endif
namespace IPC {
void ParamTraits<gfx::Range>::Write(base::Pickle* m, const gfx::Range& r) {
- m->WriteUInt32(r.start());
- m->WriteUInt32(r.end());
+ m->WriteUInt32(static_cast<uint32_t>(r.start()));
+ m->WriteUInt32(static_cast<uint32_t>(r.end()));
}
bool ParamTraits<gfx::Range>::Read(const base::Pickle* m,
@@ -36,10 +38,10 @@
}
void ParamTraits<gfx::Range>::Log(const gfx::Range& r, std::string* l) {
- l->append(base::StringPrintf("(%d, %d)", r.start(), r.end()));
+ l->append(base::StringPrintf("(%" PRIuS ", %" PRIuS ")", r.start(), r.end()));
}
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_APPLE)
void ParamTraits<gfx::ScopedRefCountedIOSurfaceMachPort>::Write(
base::Pickle* m,
const param_type p) {
@@ -97,7 +99,7 @@
}
l->append(")");
}
-#endif // defined(OS_MAC)
+#endif // BUILDFLAG(IS_APPLE)
void ParamTraits<gfx::SelectionBound>::Write(base::Pickle* m,
const param_type& p) {
diff --git a/ui/gfx/ipc/gfx_param_traits.h b/ui/gfx/ipc/gfx_param_traits.h
index e9ae63a..79901b9 100644
--- a/ui/gfx/ipc/gfx_param_traits.h
+++ b/ui/gfx/ipc/gfx_param_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,6 +7,7 @@
#include <string>
+#include "build/build_config.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/param_traits_macros.h"
#include "ui/gfx/buffer_types.h"
@@ -14,7 +15,7 @@
#include "ui/gfx/ipc/gfx_param_traits_macros.h"
#include "ui/gfx/selection_bound.h"
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_APPLE)
#include "ui/gfx/mac/io_surface.h"
#endif
@@ -34,7 +35,7 @@
static void Log(const param_type& p, std::string* l);
};
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_APPLE)
template <>
struct GFX_IPC_EXPORT ParamTraits<gfx::ScopedRefCountedIOSurfaceMachPort> {
typedef gfx::ScopedRefCountedIOSurfaceMachPort param_type;
@@ -58,7 +59,7 @@
param_type* r);
static void Log(const param_type& p, std::string* l);
};
-#endif // defined(OS_MAC)
+#endif // BUILDFLAG(IS_APPLE)
template <>
struct GFX_IPC_EXPORT ParamTraits<gfx::SelectionBound> {
diff --git a/ui/gfx/ipc/gfx_param_traits_macros.h b/ui/gfx/ipc/gfx_param_traits_macros.h
index d8ce305..98050d1 100644
--- a/ui/gfx/ipc/gfx_param_traits_macros.h
+++ b/ui/gfx/ipc/gfx_param_traits_macros.h
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,30 +11,20 @@
#include "build/build_config.h"
#include "ipc/ipc_message_macros.h"
#include "ui/gfx/ca_layer_params.h"
-#include "ui/gfx/gpu_fence_handle.h"
-#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/ipc/gfx_ipc_export.h"
-#include "ui/gfx/presentation_feedback.h"
#include "ui/gfx/selection_bound.h"
#include "ui/gfx/swap_result.h"
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
-#include "ui/gfx/native_pixmap_handle.h"
-#endif
-
#undef IPC_MESSAGE_EXPORT
#define IPC_MESSAGE_EXPORT GFX_IPC_EXPORT
-IPC_ENUM_TRAITS_MAX_VALUE(gfx::GpuMemoryBufferType,
- gfx::GPU_MEMORY_BUFFER_TYPE_LAST)
-
IPC_ENUM_TRAITS_MAX_VALUE(gfx::SwapResult, gfx::SwapResult::SWAP_RESULT_LAST)
IPC_ENUM_TRAITS_MAX_VALUE(gfx::SelectionBound::Type, gfx::SelectionBound::LAST)
IPC_STRUCT_TRAITS_BEGIN(gfx::CALayerParams)
IPC_STRUCT_TRAITS_MEMBER(is_empty)
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
IPC_STRUCT_TRAITS_MEMBER(ca_context_id)
IPC_STRUCT_TRAITS_MEMBER(io_surface_mach_port)
IPC_STRUCT_TRAITS_MEMBER(pixel_size)
@@ -42,52 +32,6 @@
#endif
IPC_STRUCT_TRAITS_END()
-IPC_STRUCT_TRAITS_BEGIN(gfx::GpuMemoryBufferHandle)
- IPC_STRUCT_TRAITS_MEMBER(id)
- IPC_STRUCT_TRAITS_MEMBER(type)
- IPC_STRUCT_TRAITS_MEMBER(region)
- IPC_STRUCT_TRAITS_MEMBER(offset)
- IPC_STRUCT_TRAITS_MEMBER(stride)
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
- IPC_STRUCT_TRAITS_MEMBER(native_pixmap_handle)
-#elif defined(OS_APPLE)
- IPC_STRUCT_TRAITS_MEMBER(io_surface)
-#elif defined(OS_WIN)
- IPC_STRUCT_TRAITS_MEMBER(dxgi_handle)
-#elif defined(OS_ANDROID)
- IPC_STRUCT_TRAITS_MEMBER(android_hardware_buffer)
-#endif
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(gfx::GpuMemoryBufferId)
- IPC_STRUCT_TRAITS_MEMBER(id)
-IPC_STRUCT_TRAITS_END()
-
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_FUCHSIA)
-IPC_STRUCT_TRAITS_BEGIN(gfx::NativePixmapPlane)
- IPC_STRUCT_TRAITS_MEMBER(stride)
- IPC_STRUCT_TRAITS_MEMBER(offset)
- IPC_STRUCT_TRAITS_MEMBER(size)
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
- IPC_STRUCT_TRAITS_MEMBER(fd)
-#elif defined(OS_FUCHSIA)
- IPC_STRUCT_TRAITS_MEMBER(vmo)
-#endif
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(gfx::NativePixmapHandle)
- IPC_STRUCT_TRAITS_MEMBER(planes)
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
- IPC_STRUCT_TRAITS_MEMBER(modifier)
-#endif
-#if defined(OS_FUCHSIA)
- IPC_STRUCT_TRAITS_MEMBER(buffer_collection_id)
- IPC_STRUCT_TRAITS_MEMBER(buffer_index)
- IPC_STRUCT_TRAITS_MEMBER(ram_coherency)
-#endif
-IPC_STRUCT_TRAITS_END()
-#endif
-
IPC_STRUCT_TRAITS_BEGIN(gfx::SwapTimings)
IPC_STRUCT_TRAITS_MEMBER(swap_start)
IPC_STRUCT_TRAITS_MEMBER(swap_end)
@@ -99,21 +43,6 @@
IPC_STRUCT_TRAITS_MEMBER(timings)
IPC_STRUCT_TRAITS_END()
-IPC_STRUCT_TRAITS_BEGIN(gfx::PresentationFeedback)
- IPC_STRUCT_TRAITS_MEMBER(timestamp)
- IPC_STRUCT_TRAITS_MEMBER(interval)
- IPC_STRUCT_TRAITS_MEMBER(flags)
-IPC_STRUCT_TRAITS_END()
-
-IPC_STRUCT_TRAITS_BEGIN(gfx::GpuFenceHandle)
-#if defined(OS_POSIX)
- IPC_STRUCT_TRAITS_MEMBER(owned_fd)
-#endif
-#if defined(OS_WIN)
- IPC_STRUCT_TRAITS_MEMBER(owned_handle)
-#endif
-IPC_STRUCT_TRAITS_END()
-
#undef IPC_MESSAGE_EXPORT
#define IPC_MESSAGE_EXPORT
diff --git a/ui/gfx/ipc/skia/BUILD.gn b/ui/gfx/ipc/skia/BUILD.gn
index fcb670e..b96b1c7 100644
--- a/ui/gfx/ipc/skia/BUILD.gn
+++ b/ui/gfx/ipc/skia/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/ui/gfx/ipc/skia/gfx_skia_ipc_export.h b/ui/gfx/ipc/skia/gfx_skia_ipc_export.h
index 8ea331d..0872eef 100644
--- a/ui/gfx/ipc/skia/gfx_skia_ipc_export.h
+++ b/ui/gfx/ipc/skia/gfx_skia_ipc_export.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ipc/skia/gfx_skia_param_traits.cc b/ui/gfx/ipc/skia/gfx_skia_param_traits.cc
index 9da1955..b4142ed 100644
--- a/ui/gfx/ipc/skia/gfx_skia_param_traits.cc
+++ b/ui/gfx/ipc/skia/gfx_skia_param_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -65,8 +65,7 @@
void ParamTraits<SkBitmap>::Write(base::Pickle* m, const SkBitmap& p) {
WriteParam(m, p.info());
size_t pixel_size = p.computeByteSize();
- m->WriteData(reinterpret_cast<const char*>(p.getPixels()),
- static_cast<int>(pixel_size));
+ m->WriteData(reinterpret_cast<const char*>(p.getPixels()), pixel_size);
}
bool ParamTraits<SkBitmap>::Read(const base::Pickle* m,
@@ -77,15 +76,14 @@
return false;
const char* bitmap_data;
- int bitmap_data_size = 0;
+ size_t bitmap_data_size = 0;
if (!iter->ReadData(&bitmap_data, &bitmap_data_size))
return false;
- // ReadData() only returns true if bitmap_data_size >= 0.
if (!r->tryAllocPixels(image_info))
return false;
- if (static_cast<size_t>(bitmap_data_size) != r->computeByteSize())
+ if (bitmap_data_size != r->computeByteSize())
return false;
memcpy(r->getPixels(), bitmap_data, bitmap_data_size);
return true;
@@ -97,38 +95,25 @@
}
void ParamTraits<gfx::Transform>::Write(base::Pickle* m, const param_type& p) {
- SkScalar column_major_data[16];
- p.matrix().asColMajorf(column_major_data);
+ float column_major_data[16];
+ p.GetColMajorF(column_major_data);
// We do this in a single write for performance reasons.
- m->WriteBytes(&column_major_data, sizeof(SkScalar) * 16);
+ m->WriteBytes(&column_major_data, sizeof(column_major_data));
}
bool ParamTraits<gfx::Transform>::Read(const base::Pickle* m,
base::PickleIterator* iter,
param_type* r) {
const char* column_major_data;
- if (!iter->ReadBytes(&column_major_data, sizeof(SkScalar) * 16))
+ if (!iter->ReadBytes(&column_major_data, sizeof(float) * 16))
return false;
- r->matrix().setColMajor(reinterpret_cast<const SkScalar*>(column_major_data));
+ *r = gfx::Transform::ColMajorF(
+ reinterpret_cast<const float*>(column_major_data));
return true;
}
-void ParamTraits<gfx::Transform>::Log(
- const param_type& p, std::string* l) {
-#ifdef SK_SCALAR_IS_FLOAT
- float row_major_data[16];
- p.matrix().asRowMajorf(row_major_data);
-#else
- double row_major_data[16];
- p.matrix().asRowMajord(row_major_data);
-#endif
- l->append("(");
- for (int i = 0; i < 16; ++i) {
- if (i > 0)
- l->append(", ");
- LogParam(row_major_data[i], l);
- }
- l->append(") ");
+void ParamTraits<gfx::Transform>::Log(const param_type& p, std::string* l) {
+ l->append(p.ToString());
}
} // namespace IPC
diff --git a/ui/gfx/ipc/skia/gfx_skia_param_traits.h b/ui/gfx/ipc/skia/gfx_skia_param_traits.h
index 3267c7d..f16a9f0 100644
--- a/ui/gfx/ipc/skia/gfx_skia_param_traits.h
+++ b/ui/gfx/ipc/skia/gfx_skia_param_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/ipc/skia/gfx_skia_param_traits_macros.h b/ui/gfx/ipc/skia/gfx_skia_param_traits_macros.h
index ada9951..d80f845 100644
--- a/ui/gfx/ipc/skia/gfx_skia_param_traits_macros.h
+++ b/ui/gfx/ipc/skia/gfx_skia_param_traits_macros.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/linux/BUILD.gn b/ui/gfx/linux/BUILD.gn
index 3d02d93..e7bd49e 100644
--- a/ui/gfx/linux/BUILD.gn
+++ b/ui/gfx/linux/BUILD.gn
@@ -1,12 +1,11 @@
-# Copyright 2018 The Chromium Authors. All rights reserved.
+# Copyright 2018 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//build/config/ozone.gni")
import("//build/config/ui.gni")
-assert(use_x11 || ozone_platform_drm || ozone_platform_wayland ||
- ozone_platform_x11)
+assert(ozone_platform_drm || ozone_platform_wayland || ozone_platform_x11)
source_set("drm") {
sources = [
@@ -46,7 +45,7 @@
]
}
-if (use_x11 || ozone_platform_x11) {
+if (ozone_platform_x11) {
component("gpu_memory_buffer_support_x11") {
sources = [
"gpu_memory_buffer_support_x11.cc",
diff --git a/ui/gfx/linux/OWNERS b/ui/gfx/linux/OWNERS
index c46d06f..a09a7e6 100644
--- a/ui/gfx/linux/OWNERS
+++ b/ui/gfx/linux/OWNERS
@@ -1,6 +1,5 @@
dcastagna@chromium.org
dnicoara@chromium.org
-dongseong.hwang@chromium.org
msisov@igalia.com
rjkroege@chromium.org
spang@chromium.org
diff --git a/ui/gfx/linux/client_native_pixmap_dmabuf.cc b/ui/gfx/linux/client_native_pixmap_dmabuf.cc
index 1befc6b..ed43aaf 100644
--- a/ui/gfx/linux/client_native_pixmap_dmabuf.cc
+++ b/ui/gfx/linux/client_native_pixmap_dmabuf.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -50,8 +50,31 @@
namespace {
+void* MapPlane(const NativePixmapPlane& plane) {
+ // The |size_to_map| computation has been determined to be valid in
+ // ClientNativePixmapFactoryDmabuf::ImportFromHandle().
+ const size_t size_to_map =
+ base::CheckAdd(plane.size, plane.offset).ValueOrDie<size_t>();
+ void* data = mmap(nullptr, size_to_map, (PROT_READ | PROT_WRITE), MAP_SHARED,
+ plane.fd.get(), 0);
+ if (data == MAP_FAILED) {
+ logging::SystemErrorCode mmap_error = logging::GetLastSystemErrorCode();
+ if (mmap_error == ENOMEM)
+ base::TerminateBecauseOutOfMemory(size_to_map);
+ LOG(ERROR) << "Failed to mmap dmabuf: "
+ << logging::SystemErrorCodeToString(mmap_error);
+ return nullptr;
+ }
+ return data;
+}
+
void PrimeSyncStart(int dmabuf_fd) {
- struct dma_buf_sync sync_start = {0};
+ struct dma_buf_sync sync_start;
+
+ // Do memset() instead of aggregate initialization because the latter can
+ // behave unintuitively with unions in C++, and we probably should not assume
+ // that dma_buf_sync will never contain a union.
+ memset(&sync_start, 0, sizeof(sync_start));
sync_start.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_RW;
int rv = HANDLE_EINTR(ioctl(dmabuf_fd, DMA_BUF_IOCTL_SYNC, &sync_start));
@@ -61,6 +84,11 @@
void PrimeSyncEnd(int dmabuf_fd) {
struct dma_buf_sync sync_end = {0};
+ // Do memset() instead of aggregate initialization because the latter can
+ // behave unintuitively with unions in C++, and we probably should not assume
+ // that dma_buf_sync will never contain a union.
+ memset(&sync_end, 0, sizeof(sync_end));
+
sync_end.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW;
int rv = HANDLE_EINTR(ioctl(dmabuf_fd, DMA_BUF_IOCTL_SYNC, &sync_end));
PLOG_IF(ERROR, rv) << "Failed DMA_BUF_SYNC_END";
@@ -179,56 +207,13 @@
ClientNativePixmapDmaBuf::ImportFromDmabuf(gfx::NativePixmapHandle handle,
const gfx::Size& size,
gfx::BufferFormat format) {
- std::array<PlaneInfo, kMaxPlanes> plane_info;
-
- size_t expected_planes = gfx::NumberOfPlanesForLinearBufferFormat(format);
- if (expected_planes == 0 || handle.planes.size() != expected_planes) {
+ if (handle.planes.size() > kMaxPlanes)
return nullptr;
- }
+ std::array<PlaneInfo, kMaxPlanes> plane_info;
for (size_t i = 0; i < handle.planes.size(); ++i) {
- // Verify that the plane buffer has appropriate size.
- const size_t plane_stride =
- base::strict_cast<size_t>(handle.planes[i].stride);
- size_t min_stride = 0;
- size_t subsample_factor = SubsamplingFactorForBufferFormat(format, i);
- base::CheckedNumeric<size_t> plane_height =
- (base::CheckedNumeric<size_t>(size.height()) + subsample_factor - 1) /
- subsample_factor;
- if (!gfx::RowSizeForBufferFormatChecked(size.width(), format, i,
- &min_stride) ||
- plane_stride < min_stride) {
- return nullptr;
- }
- base::CheckedNumeric<size_t> min_size =
- base::CheckedNumeric<size_t>(plane_stride) * plane_height;
- if (!min_size.IsValid() || handle.planes[i].size < min_size.ValueOrDie())
- return nullptr;
-
- // The stride must be a valid integer in order to be consistent with the
- // GpuMemoryBuffer::stride() API. Also, refer to http://crbug.com/1093644#c1
- // for some comments on this check and others in this method.
- if (!base::IsValueInRangeForNumericType<int>(plane_stride))
- return nullptr;
-
- const size_t map_size = base::checked_cast<size_t>(handle.planes[i].size);
- plane_info[i].offset = handle.planes[i].offset;
- plane_info[i].size = map_size;
-
- void* data = mmap(nullptr, map_size + handle.planes[i].offset,
- (PROT_READ | PROT_WRITE), MAP_SHARED,
- handle.planes[i].fd.get(), 0);
-
- if (data == MAP_FAILED) {
- logging::SystemErrorCode mmap_error = logging::GetLastSystemErrorCode();
- if (mmap_error == ENOMEM)
- base::TerminateBecauseOutOfMemory(map_size +
- handle.planes[i].offset);
- LOG(ERROR) << "Failed to mmap dmabuf: "
- << logging::SystemErrorCodeToString(mmap_error);
- return nullptr;
- }
- plane_info[i].data = data;
+ plane_info[i].offset = base::checked_cast<size_t>(handle.planes[i].offset);
+ plane_info[i].size = base::checked_cast<size_t>(handle.planes[i].size);
}
return base::WrapUnique(new ClientNativePixmapDmaBuf(std::move(handle), size,
@@ -251,15 +236,28 @@
bool ClientNativePixmapDmaBuf::Map() {
TRACE_EVENT0("drm", "DmaBuf:Map");
- for (size_t i = 0; i < pixmap_handle_.planes.size(); ++i)
- PrimeSyncStart(pixmap_handle_.planes[i].fd.get());
+ if (!mapped_) {
+ TRACE_EVENT0("drm", "DmaBuf:InitialMap");
+ for (size_t i = 0; i < pixmap_handle_.planes.size(); ++i) {
+ void* data = MapPlane(pixmap_handle_.planes[i]);
+ if (!data)
+ return false;
+ plane_info_[i].data = data;
+ }
+ mapped_ = true;
+ }
+
+ for (const auto& plane : pixmap_handle_.planes)
+ PrimeSyncStart(plane.fd.get());
+
return true;
}
void ClientNativePixmapDmaBuf::Unmap() {
TRACE_EVENT0("drm", "DmaBuf:Unmap");
- for (size_t i = 0; i < pixmap_handle_.planes.size(); ++i)
- PrimeSyncEnd(pixmap_handle_.planes[i].fd.get());
+ DCHECK(mapped_);
+ for (const auto& plane : pixmap_handle_.planes)
+ PrimeSyncEnd(plane.fd.get());
}
size_t ClientNativePixmapDmaBuf::GetNumberOfPlanes() const {
@@ -268,6 +266,7 @@
void* ClientNativePixmapDmaBuf::GetMemoryAddress(size_t plane) const {
DCHECK_LT(plane, pixmap_handle_.planes.size());
+ CHECK(mapped_);
return static_cast<uint8_t*>(plane_info_[plane].data) +
plane_info_[plane].offset;
}
diff --git a/ui/gfx/linux/client_native_pixmap_dmabuf.h b/ui/gfx/linux/client_native_pixmap_dmabuf.h
index 7c8c80e..48a2ce0 100644
--- a/ui/gfx/linux/client_native_pixmap_dmabuf.h
+++ b/ui/gfx/linux/client_native_pixmap_dmabuf.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,7 +11,7 @@
#include <memory>
#include "base/files/scoped_file.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/client_native_pixmap.h"
#include "ui/gfx/geometry/size.h"
@@ -25,6 +25,10 @@
static GFX_EXPORT bool IsConfigurationSupported(gfx::BufferFormat format,
gfx::BufferUsage usage);
+ // Note: |handle| is expected to have been validated as in
+ // ClientNativePixmapFactoryDmabuf::ImportFromHandle().
+ // TODO(andrescj): consider not exposing this class outside of
+ // client_native_pixmap_factory_dmabuf.cc.
static std::unique_ptr<gfx::ClientNativePixmap> ImportFromDmabuf(
gfx::NativePixmapHandle handle,
const gfx::Size& size,
@@ -52,7 +56,7 @@
PlaneInfo(PlaneInfo&& plane_info);
~PlaneInfo();
- void* data = nullptr;
+ raw_ptr<void> data = nullptr;
size_t offset = 0;
size_t size = 0;
};
@@ -62,7 +66,8 @@
const gfx::NativePixmapHandle pixmap_handle_;
const gfx::Size size_;
- const std::array<PlaneInfo, kMaxPlanes> plane_info_;
+ std::array<PlaneInfo, kMaxPlanes> plane_info_;
+ bool mapped_ = false;
};
} // namespace gfx
diff --git a/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc b/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
index 9fe3f7d..40ed012 100644
--- a/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
+++ b/ui/gfx/linux/client_native_pixmap_factory_dmabuf.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,7 +6,7 @@
#include <utility>
-#include "base/macros.h"
+#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
@@ -80,9 +80,48 @@
case gfx::BufferUsage::CAMERA_AND_CPU_READ_WRITE:
case gfx::BufferUsage::SCANOUT_VEA_CPU_READ:
case gfx::BufferUsage::VEA_READ_CAMERA_AND_CPU_READ_WRITE:
- case gfx::BufferUsage::SCANOUT_FRONT_RENDERING:
+ case gfx::BufferUsage::SCANOUT_FRONT_RENDERING: {
+ if (!CanFitImageForSizeAndFormat(
+ handle, size, format, /*assume_single_memory_object=*/false)) {
+ return nullptr;
+ }
+
+ for (size_t i = 0; i < handle.planes.size(); ++i) {
+ if (!base::IsValueInRangeForNumericType<size_t>(
+ handle.planes[i].offset) ||
+ !base::IsValueInRangeForNumericType<size_t>(
+ handle.planes[i].size)) {
+ return nullptr;
+ }
+
+ if (!handle.planes[i].fd.is_valid())
+ return nullptr;
+
+ const int fd = handle.planes[i].fd.get();
+ const off_t dma_buf_size = lseek(fd, /*offset=*/0, SEEK_END);
+ if (dma_buf_size == static_cast<off_t>(-1)) {
+ PLOG(ERROR) << "Failed to get the size of the dma-buf";
+ return nullptr;
+ }
+ if (lseek(fd, /*offset=*/0, SEEK_SET) == static_cast<off_t>(-1)) {
+ PLOG(ERROR) << "Failed to reset the file offset of the dma-buf";
+ return nullptr;
+ }
+ if (!base::IsValueInRangeForNumericType<size_t>(dma_buf_size))
+ return nullptr;
+
+ base::CheckedNumeric<uint64_t> size_to_map =
+ base::CheckAdd(handle.planes[i].size, handle.planes[i].offset);
+ if (!size_to_map.IsValid<size_t>())
+ return nullptr;
+ if (size_to_map.ValueOrDie<size_t>() >
+ base::checked_cast<size_t>(dma_buf_size)) {
+ return nullptr;
+ }
+ }
return ClientNativePixmapDmaBuf::ImportFromDmabuf(std::move(handle),
size, format);
+ }
case gfx::BufferUsage::GPU_READ:
case gfx::BufferUsage::SCANOUT:
case gfx::BufferUsage::SCANOUT_VDA_WRITE:
diff --git a/ui/gfx/linux/client_native_pixmap_factory_dmabuf.h b/ui/gfx/linux/client_native_pixmap_factory_dmabuf.h
index 7f802a6..7427620 100644
--- a/ui/gfx/linux/client_native_pixmap_factory_dmabuf.h
+++ b/ui/gfx/linux/client_native_pixmap_factory_dmabuf.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/linux/drm_util_linux.cc b/ui/gfx/linux/drm_util_linux.cc
index 416fc23..7abc662 100644
--- a/ui/gfx/linux/drm_util_linux.cc
+++ b/ui/gfx/linux/drm_util_linux.cc
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -18,6 +18,8 @@
return DRM_FORMAT_R16;
case gfx::BufferFormat::RG_88:
return DRM_FORMAT_GR88;
+ case gfx::BufferFormat::RG_1616:
+ return DRM_FORMAT_GR1616;
case gfx::BufferFormat::BGR_565:
return DRM_FORMAT_RGB565;
case gfx::BufferFormat::RGBA_4444:
@@ -40,6 +42,8 @@
return DRM_FORMAT_YVU420;
case gfx::BufferFormat::YUV_420_BIPLANAR:
return DRM_FORMAT_NV12;
+ case gfx::BufferFormat::YUVA_420_TRIPLANAR:
+ return DRM_FORMAT_INVALID;
case gfx::BufferFormat::P010:
return DRM_FORMAT_P010;
}
diff --git a/ui/gfx/linux/drm_util_linux.h b/ui/gfx/linux/drm_util_linux.h
index 25aa65f..2db4949 100644
--- a/ui/gfx/linux/drm_util_linux.h
+++ b/ui/gfx/linux/drm_util_linux.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/linux/fontconfig_util.cc b/ui/gfx/linux/fontconfig_util.cc
index 6f877d8..8e55aa4 100644
--- a/ui/gfx/linux/fontconfig_util.cc
+++ b/ui/gfx/linux/fontconfig_util.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,13 +6,28 @@
#include <fontconfig/fontconfig.h>
+#include "base/memory/raw_ptr.h"
#include "base/no_destructor.h"
+#include "build/chromeos_buildflags.h"
#include "ui/gfx/font_render_params.h"
+#if BUILDFLAG(IS_CHROMEOS)
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "ui/gfx/switches.h"
+#endif
+
namespace gfx {
namespace {
+#if BUILDFLAG(IS_CHROMEOS)
+constexpr base::FilePath::CharType kGoogleSansVariablePath[] =
+ FILE_PATH_LITERAL("/usr/share/fonts/google-sans/variable");
+constexpr base::FilePath::CharType kGoogleSansStaticPath[] =
+ FILE_PATH_LITERAL("/usr/share/fonts/google-sans/static");
+#endif
+
// A singleton class to wrap a global font-config configuration. The
// configuration reference counter is incremented to avoid the deletion of the
// structure while being used. This class is single-threaded and should only be
@@ -33,6 +48,21 @@
// being used (see http://crbug.com/1004254).
fc_config_ = FcConfigGetCurrent();
FcConfigReference(fc_config_);
+#if BUILDFLAG(IS_CHROMEOS)
+ if (features::UseVariableGoogleSansFont() &&
+ base::PathExists(base::FilePath(kGoogleSansVariablePath))) {
+ const FcChar8* kVariableFontPath =
+ reinterpret_cast<const FcChar8*>(kGoogleSansVariablePath);
+ // Adds the folder to the available fonts in the application. Returns
+ // false only when fonts cannot be added due to "allocation failure".
+ // https://www.freedesktop.org/software/fontconfig/fontconfig-devel/fcconfigappfontadddir.html
+ CHECK(FcConfigAppFontAddDir(fc_config_, kVariableFontPath));
+ } else {
+ const FcChar8* kStaticFontPath =
+ reinterpret_cast<const FcChar8*>(kGoogleSansStaticPath);
+ CHECK(FcConfigAppFontAddDir(fc_config_, kStaticFontPath));
+ }
+#endif
// Set rescan interval to 0 to disable re-scan. Re-scanning in the
// background is a source of thread safety issues.
@@ -44,7 +74,7 @@
GlobalFontConfig(const GlobalFontConfig&) = delete;
GlobalFontConfig& operator=(const GlobalFontConfig&) = delete;
- ~GlobalFontConfig() { FcConfigDestroy(fc_config_); }
+ ~GlobalFontConfig() { FcConfigDestroy(fc_config_.ExtractAsDangling()); }
// Retrieve the native font-config FcConfig pointer.
FcConfig* Get() const {
@@ -65,7 +95,7 @@
}
private:
- FcConfig* fc_config_ = nullptr;
+ raw_ptr<FcConfig> fc_config_ = nullptr;
};
// Converts Fontconfig FC_HINT_STYLE to FontRenderParams::Hinting.
diff --git a/ui/gfx/linux/fontconfig_util.h b/ui/gfx/linux/fontconfig_util.h
index c8cb2ae..04f4665 100644
--- a/ui/gfx/linux/fontconfig_util.h
+++ b/ui/gfx/linux/fontconfig_util.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/linux/fontconfig_util_unittest.cc b/ui/gfx/linux/fontconfig_util_unittest.cc
index 5c4d7d1..34f708c 100644
--- a/ui/gfx/linux/fontconfig_util_unittest.cc
+++ b/ui/gfx/linux/fontconfig_util_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/linux/gbm_buffer.h b/ui/gfx/linux/gbm_buffer.h
index a9805d9..f94d4f9 100644
--- a/ui/gfx/linux/gbm_buffer.h
+++ b/ui/gfx/linux/gbm_buffer.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -29,6 +29,7 @@
virtual gfx::BufferFormat GetBufferFormat() const = 0;
virtual bool AreFdsValid() const = 0;
virtual size_t GetNumPlanes() const = 0;
+ virtual bool SupportsZeroCopyWebGPUImport() const = 0;
virtual int GetPlaneFd(size_t plane) const = 0;
virtual uint32_t GetPlaneHandle(size_t plane) const = 0;
virtual uint32_t GetPlaneStride(size_t plane) const = 0;
diff --git a/ui/gfx/linux/gbm_defines.h b/ui/gfx/linux/gbm_defines.h
index b663173..0045e22 100644
--- a/ui/gfx/linux/gbm_defines.h
+++ b/ui/gfx/linux/gbm_defines.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/linux/gbm_device.h b/ui/gfx/linux/gbm_device.h
index 50f7fe5..8fd34e8 100644
--- a/ui/gfx/linux/gbm_device.h
+++ b/ui/gfx/linux/gbm_device.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,7 +9,6 @@
#include <memory>
#include "base/files/file.h"
-#include "base/macros.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_pixmap_handle.h"
@@ -33,6 +32,8 @@
uint32_t format,
const gfx::Size& size,
gfx::NativePixmapHandle handle) = 0;
+
+ virtual bool CanCreateBufferForFormat(uint32_t format) = 0;
};
} // namespace ui
diff --git a/ui/gfx/linux/gbm_util.cc b/ui/gfx/linux/gbm_util.cc
index b9adad9..3c338d3 100644
--- a/ui/gfx/linux/gbm_util.cc
+++ b/ui/gfx/linux/gbm_util.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/linux/gbm_util.h b/ui/gfx/linux/gbm_util.h
index 7b45b4a..6ac3070 100644
--- a/ui/gfx/linux/gbm_util.h
+++ b/ui/gfx/linux/gbm_util.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/linux/gbm_wrapper.cc b/ui/gfx/linux/gbm_wrapper.cc
index 04417ff..15b5316 100644
--- a/ui/gfx/linux/gbm_wrapper.cc
+++ b/ui/gfx/linux/gbm_wrapper.cc
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,6 +9,8 @@
#include <utility>
#include "base/logging.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ptr_exclusion.h"
#include "base/posix/eintr_wrapper.h"
#include "skia/ext/legacy_display_globals.h"
#include "third_party/skia/include/core/SkSurface.h"
@@ -29,56 +31,20 @@
namespace {
-// Function availability can be tested by checking if the address of gbm_* is
-// not nullptr.
-#define WEAK_GBM_FN(x) extern "C" __attribute__((weak)) decltype(x) x
-
-// TODO(https://crbug.com/784010): Remove these once support for Ubuntu Trusty
-// is dropped.
-WEAK_GBM_FN(gbm_bo_map);
-WEAK_GBM_FN(gbm_bo_unmap);
-
-// TODO(https://crbug.com/784010): Remove these once support for Ubuntu Trusty
-// and Debian Stretch are dropped.
-WEAK_GBM_FN(gbm_bo_create_with_modifiers);
-WEAK_GBM_FN(gbm_bo_get_handle_for_plane);
-WEAK_GBM_FN(gbm_bo_get_modifier);
-WEAK_GBM_FN(gbm_bo_get_offset);
-WEAK_GBM_FN(gbm_bo_get_plane_count);
-WEAK_GBM_FN(gbm_bo_get_stride_for_plane);
-
-bool HaveGbmMap() {
- return gbm_bo_map && gbm_bo_unmap;
-}
-
-bool HaveGbmModifiers() {
- return gbm_bo_create_with_modifiers && gbm_bo_get_modifier;
-}
-
-bool HaveGbmMultiplane() {
- return gbm_bo_get_handle_for_plane && gbm_bo_get_offset &&
- gbm_bo_get_plane_count && gbm_bo_get_stride_for_plane;
-}
-
uint32_t GetHandleForPlane(struct gbm_bo* bo, int plane) {
- CHECK(HaveGbmMultiplane() || plane == 0);
- return HaveGbmMultiplane() ? gbm_bo_get_handle_for_plane(bo, plane).u32
- : gbm_bo_get_handle(bo).u32;
+ return gbm_bo_get_handle_for_plane(bo, plane).u32;
}
uint32_t GetStrideForPlane(struct gbm_bo* bo, int plane) {
- CHECK(HaveGbmMultiplane() || plane == 0);
- return HaveGbmMultiplane() ? gbm_bo_get_stride_for_plane(bo, plane)
- : gbm_bo_get_stride(bo);
+ return gbm_bo_get_stride_for_plane(bo, plane);
}
uint32_t GetOffsetForPlane(struct gbm_bo* bo, int plane) {
- CHECK(HaveGbmMultiplane() || plane == 0);
- return HaveGbmMultiplane() ? gbm_bo_get_offset(bo, plane) : 0;
+ return gbm_bo_get_offset(bo, plane);
}
int GetPlaneCount(struct gbm_bo* bo) {
- return HaveGbmMultiplane() ? gbm_bo_get_plane_count(bo) : 1;
+ return gbm_bo_get_plane_count(bo);
}
int GetPlaneFdForBo(gbm_bo* bo, size_t plane) {
@@ -153,14 +119,16 @@
format_modifier_(modifier),
flags_(flags),
size_(size),
- handle_(std::move(handle)) {}
+ handle_(std::move(handle)) {
+ handle_.supports_zero_copy_webgpu_import = SupportsZeroCopyWebGPUImport();
+ }
Buffer(const Buffer&) = delete;
Buffer& operator=(const Buffer&) = delete;
~Buffer() override {
DCHECK(!mmap_data_);
- gbm_bo_destroy(bo_);
+ gbm_bo_destroy(bo_.ExtractAsDangling());
}
uint32_t GetFormat() const override { return format_; }
@@ -187,6 +155,21 @@
DCHECK_LT(plane, handle_.planes.size());
return handle_.planes[plane].fd.get();
}
+
+ bool SupportsZeroCopyWebGPUImport() const override {
+ // NOT supported if the buffer is multi-planar and its planes are disjoint.
+ size_t plane_count = GetNumPlanes();
+ if (plane_count > 1) {
+ uint32_t handle = GetPlaneHandle(0);
+ for (size_t plane = 1; plane < plane_count; ++plane) {
+ if (GetPlaneHandle(plane) != handle) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
uint32_t GetPlaneStride(size_t plane) const override {
DCHECK_LT(plane, handle_.planes.size());
return handle_.planes[plane].stride;
@@ -209,7 +192,6 @@
}
sk_sp<SkSurface> GetSurface() override {
- CHECK(HaveGbmMap());
DCHECK(!mmap_data_);
uint32_t stride;
void* addr;
@@ -233,14 +215,15 @@
private:
static void UnmapGbmBo(void* pixels, void* context) {
- CHECK(HaveGbmMap());
Buffer* buffer = static_cast<Buffer*>(context);
gbm_bo_unmap(buffer->bo_, buffer->mmap_data_);
buffer->mmap_data_ = nullptr;
}
- gbm_bo* const bo_;
- void* mmap_data_ = nullptr;
+ raw_ptr<gbm_bo> bo_;
+ // This field is not a raw_ptr<> because it was filtered by the rewriter for:
+ // #addr-of
+ RAW_PTR_EXCLUSION void* mmap_data_ = nullptr;
const uint32_t format_;
const uint64_t format_modifier_;
@@ -248,7 +231,7 @@
const gfx::Size size_;
- const gfx::NativePixmapHandle handle_;
+ gfx::NativePixmapHandle handle_;
};
std::unique_ptr<Buffer> CreateBufferForBO(struct gbm_bo* bo,
@@ -258,7 +241,7 @@
DCHECK(bo);
gfx::NativePixmapHandle handle;
- const uint64_t modifier = HaveGbmModifiers() ? gbm_bo_get_modifier(bo) : 0;
+ const uint64_t modifier = gbm_bo_get_modifier(bo);
const int plane_count = GetPlaneCount(bo);
// The Mesa's gbm implementation explicitly checks whether plane count <= and
// returns 1 if the condition is true. Nevertheless, use a DCHECK here to make
@@ -325,12 +308,51 @@
const std::vector<uint64_t>& modifiers) override {
if (modifiers.empty())
return CreateBuffer(format, size, flags);
- CHECK(HaveGbmModifiers());
- struct gbm_bo* bo = gbm_bo_create_with_modifiers(
- device_, size.width(), size.height(), format, modifiers.data(),
- modifiers.size());
- if (!bo)
+
+ std::vector<uint64_t> filtered_modifiers =
+ GetFilteredModifiers(format, flags, modifiers);
+ struct gbm_bo* bo = nullptr;
+ while (filtered_modifiers.size() > 0) {
+ bo = gbm_bo_create_with_modifiers(device_, size.width(), size.height(),
+ format, filtered_modifiers.data(),
+ filtered_modifiers.size());
+ if (!bo) {
+ return nullptr;
+ }
+
+ struct gbm_import_fd_modifier_data fd_data;
+ fd_data.width = size.width();
+ fd_data.height = size.height();
+ fd_data.format = format;
+ fd_data.num_fds = gbm_bo_get_plane_count(bo);
+ fd_data.modifier = gbm_bo_get_modifier(bo);
+
+ // Store fds in the vector of base::ScopedFDs. Will be released
+ // automatically.
+ std::vector<base::ScopedFD> fds;
+ for (size_t i = 0; i < static_cast<size_t>(fd_data.num_fds); ++i) {
+ fds.emplace_back(GetPlaneFdForBo(bo, i));
+ fd_data.fds[i] = fds.back().get();
+ fd_data.strides[i] = gbm_bo_get_stride_for_plane(bo, i);
+ fd_data.offsets[i] = gbm_bo_get_offset(bo, i);
+ }
+
+ struct gbm_bo* bo_import =
+ gbm_bo_import(device_, GBM_BO_IMPORT_FD_MODIFIER, &fd_data, flags);
+ if (bo_import) {
+ gbm_bo_destroy(bo_import);
+ break;
+ } else {
+ gbm_bo_destroy(bo);
+ bo = nullptr;
+ AddModifierToBlocklist(format, flags, fd_data.modifier);
+ filtered_modifiers =
+ GetFilteredModifiers(format, flags, filtered_modifiers);
+ }
+ }
+ if (!bo) {
return nullptr;
+ }
return CreateBufferForBO(bo, format, size, flags);
}
@@ -339,18 +361,19 @@
uint32_t format,
const gfx::Size& size,
gfx::NativePixmapHandle handle) override {
- DCHECK_EQ(handle.planes[0].offset, 0u);
+ if (handle.planes.empty()) {
+ LOG(ERROR) << "Importing handle with no planes";
+ return nullptr;
+ }
+ if (handle.planes[0].offset != 0u) {
+ LOG(ERROR) << "Unsupported handle: expected an offset of 0 for the first "
+ "plane; got "
+ << handle.planes[0].offset;
+ return nullptr;
+ }
- // Try to use scanout if supported.
- int gbm_flags = GBM_BO_USE_SCANOUT;
-#if defined(MINIGBM)
- gbm_flags |= GBM_BO_USE_TEXTURING;
-#endif
- if (!gbm_device_is_format_supported(device_, format, gbm_flags))
- gbm_flags &= ~GBM_BO_USE_SCANOUT;
-
- struct gbm_bo* bo = nullptr;
- if (!gbm_device_is_format_supported(device_, format, gbm_flags)) {
+ int gbm_flags = 0;
+ if ((gbm_flags = GetSupportedGbmFlags(format)) == 0) {
LOG(ERROR) << "gbm format not supported: " << format;
return nullptr;
}
@@ -371,7 +394,8 @@
// The fd passed to gbm_bo_import is not ref-counted and need to be
// kept open for the lifetime of the buffer.
- bo = gbm_bo_import(device_, GBM_BO_IMPORT_FD_MODIFIER, &fd_data, gbm_flags);
+ struct gbm_bo* bo =
+ gbm_bo_import(device_, GBM_BO_IMPORT_FD_MODIFIER, &fd_data, gbm_flags);
if (!bo) {
LOG(ERROR) << "nullptr returned from gbm_bo_import";
return nullptr;
@@ -381,8 +405,56 @@
size, std::move(handle));
}
+ bool CanCreateBufferForFormat(uint32_t format) override {
+ return GetSupportedGbmFlags(format) != 0;
+ }
+
+#if defined(MINIGBM)
+ int GetSupportedGbmFlags(uint32_t format) {
+ int gbm_flags = GBM_BO_USE_SCANOUT | GBM_BO_USE_TEXTURING;
+ if (gbm_device_is_format_supported(device_, format, gbm_flags))
+ return gbm_flags;
+ gbm_flags = GBM_BO_USE_TEXTURING;
+ if (gbm_device_is_format_supported(device_, format, gbm_flags))
+ return gbm_flags;
+ return 0;
+ }
+#else
+ int GetSupportedGbmFlags(uint32_t format) {
+ if (gbm_device_is_format_supported(device_, format, GBM_BO_USE_SCANOUT))
+ return GBM_BO_USE_SCANOUT;
+ return 0;
+ }
+#endif
+
private:
- gbm_device* const device_;
+ std::vector<uint64_t> GetFilteredModifiers(
+ uint32_t format,
+ uint32_t flags,
+ const std::vector<uint64_t>& modifiers) {
+ std::vector<uint64_t> filtered_modifiers = modifiers;
+
+ for (const auto& [entry_format, entry_flags, entry_modifier] :
+ modifier_blocklist_) {
+ if (entry_format == format && entry_flags == flags) {
+ filtered_modifiers.erase(
+ std::remove(filtered_modifiers.begin(), filtered_modifiers.end(),
+ entry_modifier),
+ filtered_modifiers.end());
+ }
+ }
+
+ return filtered_modifiers;
+ }
+
+ void AddModifierToBlocklist(uint32_t format,
+ uint32_t flags,
+ uint64_t modifier) {
+ modifier_blocklist_.push_back({format, flags, modifier});
+ }
+
+ const raw_ptr<gbm_device> device_;
+ std::vector<std::tuple<uint32_t, uint32_t, uint64_t>> modifier_blocklist_;
};
} // namespace gbm_wrapper
diff --git a/ui/gfx/linux/gbm_wrapper.h b/ui/gfx/linux/gbm_wrapper.h
index b06f44e..bbbe9b4 100644
--- a/ui/gfx/linux/gbm_wrapper.h
+++ b/ui/gfx/linux/gbm_wrapper.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/linux/gpu_memory_buffer_support_x11.cc b/ui/gfx/linux/gpu_memory_buffer_support_x11.cc
index 5b89bfd..193a4ed 100644
--- a/ui/gfx/linux/gpu_memory_buffer_support_x11.cc
+++ b/ui/gfx/linux/gpu_memory_buffer_support_x11.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,6 +11,8 @@
#include "base/containers/contains.h"
#include "base/debug/crash_logging.h"
+#include "base/logging.h"
+#include "base/no_destructor.h"
#include "base/posix/eintr_wrapper.h"
#include "ui/gfx/buffer_format_util.h"
#include "ui/gfx/buffer_types.h"
@@ -30,14 +32,23 @@
// Obtain an authenticated DRM fd from X11 and create a GbmDevice with it.
std::unique_ptr<ui::GbmDevice> CreateX11GbmDevice() {
+ if (getenv("RUNNING_UNDER_RR") != nullptr) {
+ LOG(WARNING) << "Running under rr, disabling dri3";
+ return nullptr;
+ }
+
auto* connection = x11::Connection::Get();
// |connection| may be nullptr in headless mode.
- if (!connection)
+ if (!connection) {
+ LOG(WARNING) << "Could not create x11 connection.";
return nullptr;
+ }
auto& dri3 = connection->dri3();
- if (!dri3.present())
+ if (!dri3.present()) {
+ LOG(WARNING) << "dri3 extension not supported.";
return nullptr;
+ }
// Let the X11 server know the DRI3 client version. This is required to use
// the DRI3 extension. We don't care about the returned server version because
@@ -69,6 +80,7 @@
gfx::BufferUsage::SCANOUT,
gfx::BufferUsage::SCANOUT_CPU_READ_WRITE,
gfx::BufferUsage::GPU_READ_CPU_READ_WRITE,
+ gfx::BufferUsage::SCANOUT_VDA_WRITE,
}) {
for (gfx::BufferFormat format : {
gfx::BufferFormat::R_8,
@@ -118,9 +130,17 @@
gfx::BufferFormat format,
const gfx::Size& size,
gfx::BufferUsage usage) {
- DCHECK(device_);
- DCHECK(base::Contains(supported_configs_,
- gfx::BufferUsageAndFormat(usage, format)));
+ if (!device_) {
+ LOG(ERROR) << "Can't create buffer -- gbm device is missing.";
+ return nullptr;
+ }
+ if (!base::Contains(supported_configs_,
+ gfx::BufferUsageAndFormat(usage, format))) {
+ LOG(ERROR) << "Can't create buffer -- unsupported config: usage="
+ << gfx::BufferUsageToString(usage)
+ << ", format=" << gfx::BufferFormatToString(format);
+ return nullptr;
+ }
static base::debug::CrashKeyString* crash_key_string =
base::debug::AllocateCrashKeyString("buffer_usage_and_format",
@@ -135,4 +155,30 @@
BufferUsageToGbmFlags(usage));
}
+bool GpuMemoryBufferSupportX11::CanCreateNativePixmapForFormat(
+ gfx::BufferFormat format) {
+ return device_ && device_->CanCreateBufferForFormat(
+ GetFourCCFormatFromBufferFormat(format));
+}
+
+std::unique_ptr<GbmBuffer> GpuMemoryBufferSupportX11::CreateBufferFromHandle(
+ const gfx::Size& size,
+ gfx::BufferFormat format,
+ gfx::NativePixmapHandle handle) {
+ if (!device_) {
+ LOG(ERROR) << "Can't create buffer from handle -- gbm device is missing.";
+ return nullptr;
+ }
+
+ static base::debug::CrashKeyString* crash_key_string =
+ base::debug::AllocateCrashKeyString("buffer_from_handle_format",
+ base::debug::CrashKeySize::Size64);
+ std::string buffer_from_handle_format = gfx::BufferFormatToString(format);
+ base::debug::ScopedCrashKeyString scoped_crash_key(
+ crash_key_string, buffer_from_handle_format.c_str());
+
+ return device_->CreateBufferFromHandle(
+ GetFourCCFormatFromBufferFormat(format), size, std::move(handle));
+}
+
} // namespace ui
diff --git a/ui/gfx/linux/gpu_memory_buffer_support_x11.h b/ui/gfx/linux/gpu_memory_buffer_support_x11.h
index 600354a..a00fc7c 100644
--- a/ui/gfx/linux/gpu_memory_buffer_support_x11.h
+++ b/ui/gfx/linux/gpu_memory_buffer_support_x11.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,6 +11,7 @@
#include "base/component_export.h"
#include "base/no_destructor.h"
#include "ui/gfx/buffer_types.h"
+#include "ui/gfx/native_pixmap_handle.h"
namespace gfx {
class Size;
@@ -31,6 +32,12 @@
const gfx::Size& size,
gfx::BufferUsage usage);
+ bool CanCreateNativePixmapForFormat(gfx::BufferFormat format);
+ std::unique_ptr<GbmBuffer> CreateBufferFromHandle(
+ const gfx::Size& size,
+ gfx::BufferFormat format,
+ gfx::NativePixmapHandle handle);
+
~GpuMemoryBufferSupportX11();
GpuMemoryBufferSupportX11(const GpuMemoryBufferSupportX11&) = delete;
@@ -41,6 +48,8 @@
return supported_configs_;
}
+ bool has_gbm_device() const { return device_ != nullptr; }
+
private:
friend class base::NoDestructor<GpuMemoryBufferSupportX11>;
diff --git a/ui/gfx/linux/native_pixmap_dmabuf.cc b/ui/gfx/linux/native_pixmap_dmabuf.cc
index 2cddfdd..3ae9349 100644
--- a/ui/gfx/linux/native_pixmap_dmabuf.cc
+++ b/ui/gfx/linux/native_pixmap_dmabuf.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -35,17 +35,17 @@
uint32_t NativePixmapDmaBuf::GetDmaBufPitch(size_t plane) const {
DCHECK_LT(plane, handle_.planes.size());
- return handle_.planes[plane].stride;
+ return base::checked_cast<uint32_t>(handle_.planes[plane].stride);
}
size_t NativePixmapDmaBuf::GetDmaBufOffset(size_t plane) const {
DCHECK_LT(plane, handle_.planes.size());
- return static_cast<size_t>(handle_.planes[plane].offset);
+ return base::checked_cast<size_t>(handle_.planes[plane].offset);
}
size_t NativePixmapDmaBuf::GetDmaBufPlaneSize(size_t plane) const {
DCHECK_LT(plane, handle_.planes.size());
- return static_cast<size_t>(handle_.planes[plane].size);
+ return base::checked_cast<size_t>(handle_.planes[plane].size);
}
uint64_t NativePixmapDmaBuf::GetBufferFormatModifier() const {
@@ -60,6 +60,12 @@
return handle_.planes.size();
}
+bool NativePixmapDmaBuf::SupportsZeroCopyWebGPUImport() const {
+ // TODO(crbug.com/1258986): Figure out how to import multi-planar pixmap into
+ // WebGPU without copy.
+ return false;
+}
+
gfx::Size NativePixmapDmaBuf::GetBufferSize() const {
return size_;
}
diff --git a/ui/gfx/linux/native_pixmap_dmabuf.h b/ui/gfx/linux/native_pixmap_dmabuf.h
index 78edc14..f12d4f5 100644
--- a/ui/gfx/linux/native_pixmap_dmabuf.h
+++ b/ui/gfx/linux/native_pixmap_dmabuf.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,8 +10,6 @@
#include <memory>
#include "base/files/scoped_file.h"
-#include "base/macros.h"
-#include "base/memory/ref_counted.h"
#include "ui/gfx/client_native_pixmap.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/native_pixmap.h"
@@ -19,7 +17,7 @@
namespace gfx {
// This class converts a gfx::NativePixmapHandle to a gfx::NativePixmap.
-// It is useful because gl::GLImageNativePixmap::Initialize only takes
+// It is useful because gpu::GLImageNativePixmap::Initialize only takes
// a gfx::NativePixmap as input.
class GFX_EXPORT NativePixmapDmaBuf : public gfx::NativePixmap {
public:
@@ -39,6 +37,7 @@
uint64_t GetBufferFormatModifier() const override;
gfx::BufferFormat GetBufferFormat() const override;
size_t GetNumberOfPlanes() const override;
+ bool SupportsZeroCopyWebGPUImport() const override;
gfx::Size GetBufferSize() const override;
uint32_t GetUniqueId() const override;
bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
diff --git a/ui/gfx/linux/native_pixmap_dmabuf_unittest.cc b/ui/gfx/linux/native_pixmap_dmabuf_unittest.cc
index 1d7ccfc..b71f12c 100644
--- a/ui/gfx/linux/native_pixmap_dmabuf_unittest.cc
+++ b/ui/gfx/linux/native_pixmap_dmabuf_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/linux/scoped_gbm_device.cc b/ui/gfx/linux/scoped_gbm_device.cc
index 951a91b..5aa03f9 100644
--- a/ui/gfx/linux/scoped_gbm_device.cc
+++ b/ui/gfx/linux/scoped_gbm_device.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/linux/scoped_gbm_device.h b/ui/gfx/linux/scoped_gbm_device.h
index 0abed15..2a7bb6e 100644
--- a/ui/gfx/linux/scoped_gbm_device.h
+++ b/ui/gfx/linux/scoped_gbm_device.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/linux/test/mock_gbm_device.cc b/ui/gfx/linux/test/mock_gbm_device.cc
index 9ea3659..40836ed 100644
--- a/ui/gfx/linux/test/mock_gbm_device.cc
+++ b/ui/gfx/linux/test/mock_gbm_device.cc
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -73,6 +73,12 @@
int GetPlaneFd(size_t plane) const override {
return planes_[plane].fd.get();
}
+
+ bool SupportsZeroCopyWebGPUImport() const override {
+ NOTIMPLEMENTED();
+ return false;
+ }
+
uint32_t GetPlaneStride(size_t plane) const override {
DCHECK_LT(plane, planes_.size());
return planes_[plane].stride;
@@ -185,4 +191,8 @@
return nullptr;
}
+bool MockGbmDevice::CanCreateBufferForFormat(uint32_t format) {
+ return true;
+}
+
} // namespace ui
diff --git a/ui/gfx/linux/test/mock_gbm_device.h b/ui/gfx/linux/test/mock_gbm_device.h
index 16c9d2d..a2d36ca 100644
--- a/ui/gfx/linux/test/mock_gbm_device.h
+++ b/ui/gfx/linux/test/mock_gbm_device.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -37,6 +37,7 @@
uint32_t format,
const gfx::Size& size,
gfx::NativePixmapHandle handle) override;
+ bool CanCreateBufferForFormat(uint32_t format) override;
private:
uint32_t next_handle_ = 0;
diff --git a/ui/gfx/mac/coordinate_conversion.h b/ui/gfx/mac/coordinate_conversion.h
index 3b75485..d280295 100644
--- a/ui/gfx/mac/coordinate_conversion.h
+++ b/ui/gfx/mac/coordinate_conversion.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mac/coordinate_conversion.mm b/ui/gfx/mac/coordinate_conversion.mm
index b31ce9e..2111434 100644
--- a/ui/gfx/mac/coordinate_conversion.mm
+++ b/ui/gfx/mac/coordinate_conversion.mm
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mac/coordinate_conversion_unittest.mm b/ui/gfx/mac/coordinate_conversion_unittest.mm
index 23f078a..f3b4b65 100644
--- a/ui/gfx/mac/coordinate_conversion_unittest.mm
+++ b/ui/gfx/mac/coordinate_conversion_unittest.mm
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,7 +9,6 @@
#include <memory>
#import "base/mac/scoped_objc_class_swizzler.h"
-#include "base/macros.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"
#include "ui/gfx/geometry/rect.h"
diff --git a/ui/gfx/mac/display_icc_profiles.cc b/ui/gfx/mac/display_icc_profiles.cc
index 119b652..bc88ef1 100644
--- a/ui/gfx/mac/display_icc_profiles.cc
+++ b/ui/gfx/mac/display_icc_profiles.cc
@@ -1,9 +1,10 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/mac/display_icc_profiles.h"
+#include "base/no_destructor.h"
#include "base/notreached.h"
#include "ui/gfx/icc_profile.h"
@@ -40,8 +41,8 @@
map_.clear();
// Always add Apple's sRGB profile.
- base::ScopedCFTypeRef<CFDataRef> srgb_icc(CGColorSpaceCopyICCProfile(
- CGColorSpaceCreateWithName(kCGColorSpaceSRGB)));
+ base::ScopedCFTypeRef<CFDataRef> srgb_icc(
+ CGColorSpaceCopyICCData(CGColorSpaceCreateWithName(kCGColorSpaceSRGB)));
map_[ColorSpace::CreateSRGB()] = srgb_icc;
// Add the profiles for all active displays.
@@ -65,7 +66,7 @@
if (!cg_color_space)
continue;
base::ScopedCFTypeRef<CFDataRef> icc_data(
- CGColorSpaceCopyICCProfile(cg_color_space));
+ CGColorSpaceCopyICCData(cg_color_space));
if (!icc_data)
continue;
ICCProfile icc_profile = ICCProfile::FromData(CFDataGetBytePtr(icc_data),
diff --git a/ui/gfx/mac/display_icc_profiles.h b/ui/gfx/mac/display_icc_profiles.h
index 565bb0c..ece717d 100644
--- a/ui/gfx/mac/display_icc_profiles.h
+++ b/ui/gfx/mac/display_icc_profiles.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,7 +9,6 @@
#include "base/containers/flat_map.h"
#include "base/mac/scoped_cftyperef.h"
-#include "base/macros.h"
#include "base/no_destructor.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/color_space_export.h"
diff --git a/ui/gfx/mac/io_surface.cc b/ui/gfx/mac/io_surface.cc
index 7a199bc..95d74c9 100644
--- a/ui/gfx/mac/io_surface.cc
+++ b/ui/gfx/mac/io_surface.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,7 +11,6 @@
#include "base/bits.h"
#include "base/command_line.h"
-#include "base/cxx17_backports.h"
#include "base/feature_list.h"
#include "base/logging.h"
#include "base/mac/mac_util.h"
@@ -26,8 +25,9 @@
namespace {
-const base::Feature kIOSurfaceUseNamedSRGBForREC709{
- "IOSurfaceUseNamedSRGBForREC709", base::FEATURE_ENABLED_BY_DEFAULT};
+BASE_FEATURE(kIOSurfaceUseNamedSRGBForREC709,
+ "IOSurfaceUseNamedSRGBForREC709",
+ base::FEATURE_ENABLED_BY_DEFAULT);
void AddIntegerValue(CFMutableDictionaryRef dictionary,
const CFStringRef key,
@@ -42,9 +42,19 @@
case gfx::BufferFormat::R_8:
DCHECK_EQ(plane, 0);
return 1;
+ case gfx::BufferFormat::R_16:
+ DCHECK_EQ(plane, 0);
+ return 2;
+ case gfx::BufferFormat::RG_88:
+ DCHECK_EQ(plane, 0);
+ return 2;
+ case gfx::BufferFormat::RG_1616:
+ DCHECK_EQ(plane, 0);
+ return 4;
case gfx::BufferFormat::BGRA_8888:
case gfx::BufferFormat::BGRX_8888:
case gfx::BufferFormat::RGBA_8888:
+ case gfx::BufferFormat::RGBX_8888:
case gfx::BufferFormat::BGRA_1010102:
DCHECK_EQ(plane, 0);
return 4;
@@ -53,19 +63,21 @@
return 8;
case gfx::BufferFormat::YUV_420_BIPLANAR: {
constexpr int32_t bytes_per_element[] = {1, 2};
- DCHECK_LT(static_cast<size_t>(plane), base::size(bytes_per_element));
+ DCHECK_LT(static_cast<size_t>(plane), std::size(bytes_per_element));
+ return bytes_per_element[plane];
+ }
+ case gfx::BufferFormat::YUVA_420_TRIPLANAR: {
+ constexpr int32_t bytes_per_element[] = {1, 2, 1};
+ DCHECK_LT(static_cast<size_t>(plane), std::size(bytes_per_element));
return bytes_per_element[plane];
}
case gfx::BufferFormat::P010: {
constexpr int32_t bytes_per_element[] = {2, 4};
- DCHECK_LT(static_cast<size_t>(plane), base::size(bytes_per_element));
+ DCHECK_LT(static_cast<size_t>(plane), std::size(bytes_per_element));
return bytes_per_element[plane];
}
- case gfx::BufferFormat::R_16:
- case gfx::BufferFormat::RG_88:
case gfx::BufferFormat::BGR_565:
case gfx::BufferFormat::RGBA_4444:
- case gfx::BufferFormat::RGBX_8888:
case gfx::BufferFormat::RGBA_1010102:
case gfx::BufferFormat::YVU_420:
NOTREACHED();
@@ -82,23 +94,31 @@
switch (format) {
case gfx::BufferFormat::R_8:
return 'L008';
+ case gfx::BufferFormat::RG_88:
+ return '2C08';
+ case gfx::BufferFormat::R_16:
+ return 'L016';
+ case gfx::BufferFormat::RG_1616:
+ return '2C16';
case gfx::BufferFormat::BGRA_1010102:
return 'l10r'; // little-endian ARGB2101010 full-range ARGB
case gfx::BufferFormat::BGRA_8888:
case gfx::BufferFormat::BGRX_8888:
case gfx::BufferFormat::RGBA_8888:
+ case gfx::BufferFormat::RGBX_8888:
+ // MacOS and iOS use ANGLE and do the conversion themselves and BGRA is
+ // the most optimal format.
return 'BGRA';
case gfx::BufferFormat::RGBA_F16:
return 'RGhA';
case gfx::BufferFormat::YUV_420_BIPLANAR:
return '420v';
+ case gfx::BufferFormat::YUVA_420_TRIPLANAR:
+ return 'v0a8';
case gfx::BufferFormat::P010:
return 'x420';
- case gfx::BufferFormat::R_16:
- case gfx::BufferFormat::RG_88:
case gfx::BufferFormat::BGR_565:
case gfx::BufferFormat::RGBA_4444:
- case gfx::BufferFormat::RGBX_8888:
case gfx::BufferFormat::RGBA_1010102:
// Technically RGBA_1010102 should be accepted as 'R10k', but then it won't
// be supported by CGLTexImageIOSurface2D(), so it's best to reject it here.
@@ -138,19 +158,18 @@
// Prefer using named spaces.
CFStringRef color_space_name = nullptr;
- if (__builtin_available(macos 10.12, *)) {
- if (color_space == ColorSpace::CreateSRGB() ||
- (base::FeatureList::IsEnabled(kIOSurfaceUseNamedSRGBForREC709) &&
- color_space == ColorSpace::CreateREC709())) {
- color_space_name = kCGColorSpaceSRGB;
- } else if (color_space == ColorSpace::CreateDisplayP3D65()) {
- color_space_name = kCGColorSpaceDisplayP3;
- } else if (color_space == ColorSpace::CreateExtendedSRGB()) {
- color_space_name = kCGColorSpaceExtendedSRGB;
- } else if (color_space == ColorSpace::CreateSCRGBLinear()) {
- color_space_name = kCGColorSpaceExtendedLinearSRGB;
- }
+ if (color_space == ColorSpace::CreateSRGB() ||
+ (base::FeatureList::IsEnabled(kIOSurfaceUseNamedSRGBForREC709) &&
+ color_space == ColorSpace::CreateREC709())) {
+ color_space_name = kCGColorSpaceSRGB;
+ } else if (color_space == ColorSpace::CreateDisplayP3D65()) {
+ color_space_name = kCGColorSpaceDisplayP3;
+ } else if (color_space == ColorSpace::CreateExtendedSRGB()) {
+ color_space_name = kCGColorSpaceExtendedSRGB;
+ } else if (color_space == ColorSpace::CreateSRGBLinear()) {
+ color_space_name = kCGColorSpaceExtendedLinearSRGB;
}
+
// The symbols kCGColorSpaceITUR_2020_PQ_EOTF and kCGColorSpaceITUR_2020_HLG
// have been deprecated. Claim that we were able to set the color space,
// because the path that will render these color spaces will use the
@@ -161,7 +180,7 @@
// https://crbug.com/1061723: Discussion of issues related to HLG.
if (__builtin_available(macos 10.15, *)) {
if (color_space == ColorSpace(ColorSpace::PrimaryID::BT2020,
- ColorSpace::TransferID::SMPTEST2084,
+ ColorSpace::TransferID::PQ,
ColorSpace::MatrixID::BT2020_NCL,
ColorSpace::RangeID::LIMITED)) {
if (__builtin_available(macos 11.0, *)) {
@@ -170,7 +189,7 @@
return true;
}
} else if (color_space == ColorSpace(ColorSpace::PrimaryID::BT2020,
- ColorSpace::TransferID::ARIB_STD_B67,
+ ColorSpace::TransferID::HLG,
ColorSpace::MatrixID::BT2020_NCL,
ColorSpace::RangeID::LIMITED)) {
if (__builtin_available(macos 11.0, *)) {
@@ -244,12 +263,13 @@
const size_t plane_width = (size.width() + factor - 1) / factor;
const size_t plane_height = (size.height() + factor - 1) / factor;
const size_t plane_bytes_per_element = BytesPerElement(format, plane);
- const size_t plane_bytes_per_row = IOSurfaceAlignProperty(
- kIOSurfacePlaneBytesPerRow,
- base::bits::AlignUp(plane_width, 2) * plane_bytes_per_element);
+ const size_t plane_bytes_per_row =
+ IOSurfaceAlignProperty(kIOSurfacePlaneBytesPerRow,
+ base::bits::AlignUp(plane_width, size_t{2}) *
+ plane_bytes_per_element);
const size_t plane_bytes_alloc = IOSurfaceAlignProperty(
kIOSurfacePlaneSize,
- base::bits::AlignUp(plane_height, 2) * plane_bytes_per_row);
+ base::bits::AlignUp(plane_height, size_t{2}) * plane_bytes_per_row);
const size_t plane_offset =
IOSurfaceAlignProperty(kIOSurfacePlaneOffset, total_bytes_alloc);
@@ -303,14 +323,7 @@
}
// Ensure that all IOSurfaces start as sRGB.
- if (__builtin_available(macos 10.12, *)) {
- IOSurfaceSetValue(surface, CFSTR("IOSurfaceColorSpace"), kCGColorSpaceSRGB);
- } else {
- CGColorSpaceRef color_space = base::mac::GetSRGBColorSpace();
- base::ScopedCFTypeRef<CFDataRef> color_space_icc(
- CGColorSpaceCopyICCProfile(color_space));
- IOSurfaceSetValue(surface, CFSTR("IOSurfaceColorSpace"), color_space_icc);
- }
+ IOSurfaceSetValue(surface, CFSTR("IOSurfaceColorSpace"), kCGColorSpaceSRGB);
UMA_HISTOGRAM_TIMES("GPU.IOSurface.CreateTime",
base::TimeTicks::Now() - start_time);
diff --git a/ui/gfx/mac/io_surface.h b/ui/gfx/mac/io_surface.h
index 88c6a5d..8bbe49a 100644
--- a/ui/gfx/mac/io_surface.h
+++ b/ui/gfx/mac/io_surface.h
@@ -1,11 +1,12 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_MAC_IO_SURFACE_H_
#define UI_GFX_MAC_IO_SURFACE_H_
-#include <IOSurface/IOSurface.h>
+#include <IOKit/IOReturn.h>
+#include <IOSurface/IOSurfaceRef.h>
#include <mach/mach.h>
#include "base/mac/scoped_cftyperef.h"
diff --git a/ui/gfx/mac/io_surface_hdr_metadata.cc b/ui/gfx/mac/io_surface_hdr_metadata.cc
deleted file mode 100644
index f425024..0000000
--- a/ui/gfx/mac/io_surface_hdr_metadata.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/mac/io_surface_hdr_metadata.h"
-
-#include "base/mac/foundation_util.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "ui/gfx/mojom/hdr_metadata.mojom.h"
-
-namespace gfx {
-
-namespace {
-
-// The key under which HDR metadata is attached to an IOSurface.
-const CFStringRef kCrIOSurfaceHDRMetadataKey =
- CFSTR("CrIOSurfaceHDRMetadataKey");
-
-} // namespace
-
-void IOSurfaceSetHDRMetadata(IOSurfaceRef io_surface,
- gfx::HDRMetadata hdr_metadata) {
- std::vector<uint8_t> std_data =
- gfx::mojom::HDRMetadata::Serialize(&hdr_metadata);
- base::ScopedCFTypeRef<CFDataRef> cf_data(
- CFDataCreate(nullptr, std_data.data(), std_data.size()));
- IOSurfaceSetValue(io_surface, kCrIOSurfaceHDRMetadataKey, cf_data);
-}
-
-bool IOSurfaceGetHDRMetadata(IOSurfaceRef io_surface,
- gfx::HDRMetadata& hdr_metadata) {
- base::ScopedCFTypeRef<CFTypeRef> cf_untyped(
- IOSurfaceCopyValue(io_surface, kCrIOSurfaceHDRMetadataKey));
- CFDataRef cf_data = base::mac::CFCast<CFDataRef>(cf_untyped);
- if (!cf_data)
- return false;
- const UInt8* raw_data = CFDataGetBytePtr(cf_data);
- std::vector<uint8_t> std_data(raw_data, raw_data + CFDataGetLength(cf_data));
- return gfx::mojom::HDRMetadata::Deserialize(std_data, &hdr_metadata);
-}
-
-} // namespace gfx
diff --git a/ui/gfx/mac/io_surface_hdr_metadata.h b/ui/gfx/mac/io_surface_hdr_metadata.h
deleted file mode 100644
index 1bee484..0000000
--- a/ui/gfx/mac/io_surface_hdr_metadata.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_MAC_IO_SURFACE_HDR_METADATA_H_
-#define UI_GFX_MAC_IO_SURFACE_HDR_METADATA_H_
-
-#include <IOSurface/IOSurface.h>
-
-#include "base/component_export.h"
-
-namespace gfx {
-
-struct HDRMetadata;
-
-// Attach |hdr_metadata| to |io_surface|. After this is called, any other
-// process that has opened |io_surface| will be able to read |hdr_metadata|
-// using the function IOSurfaceGetHDRMetadata.
-void COMPONENT_EXPORT(GFX_IO_SURFACE_HDR_METADATA)
- IOSurfaceSetHDRMetadata(IOSurfaceRef io_surface,
- gfx::HDRMetadata hdr_metadata);
-
-// Retrieve in |hdr_metadata| the value that was attached to |io_surface|. This
-// will return false on failure.
-bool COMPONENT_EXPORT(GFX_IO_SURFACE_HDR_METADATA)
- IOSurfaceGetHDRMetadata(IOSurfaceRef io_surface,
- gfx::HDRMetadata& hdr_metadata);
-
-} // namespace gfx
-
-#endif // UI_GFX_MAC_IO_SURFACE_HDR_METADATA_H_
diff --git a/ui/gfx/mac/io_surface_unittest.cc b/ui/gfx/mac/io_surface_unittest.cc
index 31eef23..6f68796 100644
--- a/ui/gfx/mac/io_surface_unittest.cc
+++ b/ui/gfx/mac/io_surface_unittest.cc
@@ -1,38 +1,14 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/mac/io_surface.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/hdr_metadata.h"
-#include "ui/gfx/mac/io_surface_hdr_metadata.h"
namespace gfx {
namespace {
-// Check that empty NSBezierPath is returned for empty SkPath.
-TEST(IOSurface, HDRMetadata) {
- gfx::HDRMetadata in;
- in.color_volume_metadata.primary_r = PointF(1.0, 2.0);
- in.color_volume_metadata.primary_g = PointF(4.0, 5.0);
- in.color_volume_metadata.primary_b = PointF(7.0, 8.0);
- in.color_volume_metadata.white_point = PointF(10.0, 11.0);
- in.color_volume_metadata.luminance_max = 13;
- in.color_volume_metadata.luminance_min = 14;
- in.max_content_light_level = 15;
- in.max_frame_average_light_level = 16;
-
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
- CreateIOSurface(gfx::Size(100, 100), gfx::BufferFormat::BGRA_8888));
-
- gfx::HDRMetadata out;
- EXPECT_FALSE(IOSurfaceGetHDRMetadata(io_surface, out));
- IOSurfaceSetHDRMetadata(io_surface, in);
- EXPECT_TRUE(IOSurfaceGetHDRMetadata(io_surface, out));
- EXPECT_EQ(in, out);
-}
-
TEST(IOSurface, OddSizeMultiPlanar) {
base::ScopedCFTypeRef<IOSurfaceRef> io_surface(
CreateIOSurface(gfx::Size(101, 99), gfx::BufferFormat::YUV_420_BIPLANAR));
diff --git a/ui/gfx/mac/nswindow_frame_controls.h b/ui/gfx/mac/nswindow_frame_controls.h
index d58eeca..2fe0e51 100644
--- a/ui/gfx/mac/nswindow_frame_controls.h
+++ b/ui/gfx/mac/nswindow_frame_controls.h
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mac/nswindow_frame_controls.mm b/ui/gfx/mac/nswindow_frame_controls.mm
index 3802078..2a85eee 100644
--- a/ui/gfx/mac/nswindow_frame_controls.mm
+++ b/ui/gfx/mac/nswindow_frame_controls.mm
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -16,9 +16,9 @@
void SetResizableStyleMask(NSWindow* window, bool resizable) {
NSUInteger style_mask = [window styleMask];
if (resizable)
- style_mask |= NSResizableWindowMask;
+ style_mask |= NSWindowStyleMaskResizable;
else
- style_mask &= ~NSResizableWindowMask;
+ style_mask &= ~NSWindowStyleMaskResizable;
[window setStyleMask:style_mask];
}
diff --git a/ui/gfx/mac/scoped_cocoa_disable_screen_updates.h b/ui/gfx/mac/scoped_cocoa_disable_screen_updates.h
index 1ab2e28..bdb1830 100644
--- a/ui/gfx/mac/scoped_cocoa_disable_screen_updates.h
+++ b/ui/gfx/mac/scoped_cocoa_disable_screen_updates.h
@@ -1,11 +1,10 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_MAC_SCOPED_COCOA_DISABLE_SCREEN_UPDATES_H_
#define UI_GFX_MAC_SCOPED_COCOA_DISABLE_SCREEN_UPDATES_H_
-#include "base/macros.h"
#include "ui/gfx/gfx_export.h"
namespace gfx {
diff --git a/ui/gfx/mac/scoped_cocoa_disable_screen_updates.mm b/ui/gfx/mac/scoped_cocoa_disable_screen_updates.mm
index b31792b..bf2a877 100644
--- a/ui/gfx/mac/scoped_cocoa_disable_screen_updates.mm
+++ b/ui/gfx/mac/scoped_cocoa_disable_screen_updates.mm
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/BUILD.gn b/ui/gfx/mojom/BUILD.gn
index 7c30bf8..b511389 100644
--- a/ui/gfx/mojom/BUILD.gn
+++ b/ui/gfx/mojom/BUILD.gn
@@ -1,7 +1,8 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
+# Copyright 2016 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/features.gni")
import("//build/config/ozone.gni")
import("//mojo/public/tools/bindings/mojom.gni")
@@ -17,10 +18,12 @@
"delegated_ink_point_renderer.mojom",
"display_color_spaces.mojom",
"font_render_params.mojom",
+ "frame_data.mojom",
"gpu_extra_info.mojom",
"gpu_fence_handle.mojom",
"hdr_metadata.mojom",
"hdr_static_metadata.mojom",
+ "linear_gradient.mojom",
"mask_filter_info.mojom",
"overlay_priority_hint.mojom",
"overlay_transform.mojom",
@@ -32,15 +35,20 @@
"transform.mojom",
]
+ if (is_apple) {
+ sources += [ "ca_layer_result.mojom" ]
+ }
+
public_deps = [
":native_handle_types",
"//mojo/public/mojom/base",
"//skia/public/mojom",
"//ui/gfx/geometry/mojom",
]
+ webui_module_path = "chrome://resources/mojo/ui/gfx/mojom"
enabled_features = []
- if (use_x11 || ozone_platform_x11) {
+ if (ozone_platform_x11) {
enabled_features += [ "enable_x11_params" ]
}
@@ -196,12 +204,12 @@
{
types = [
{
- mojom = "gfx.mojom.CALayerParams"
- cpp = "::gfx::CALayerParams"
+ mojom = "gfx.mojom.CALayerResult"
+ cpp = "::gfx::CALayerResult"
},
]
- traits_sources = [ "ca_layer_params_mojom_traits.cc" ]
- traits_headers = [ "ca_layer_params_mojom_traits.h" ]
+ traits_sources = [ "ca_layer_result_mojom_traits.cc" ]
+ traits_headers = [ "ca_layer_result_mojom_traits.h" ]
traits_public_deps = [ "//ui/gfx" ]
},
{
@@ -306,10 +314,47 @@
]
traits_sources = [ "mask_filter_info_mojom_traits.cc" ]
traits_headers = [ "mask_filter_info_mojom_traits.h" ]
+ traits_public_deps = [ "//ui/gfx/geometry:geometry_skia" ]
+ },
+ {
+ types = [
+ {
+ mojom = "gfx.mojom.LinearGradient"
+ cpp = "::gfx::LinearGradient"
+ },
+ ]
+ traits_sources = [ "linear_gradient_mojom_traits.cc" ]
+ traits_headers = [ "linear_gradient_mojom_traits.h" ]
+ traits_public_deps = [ "//ui/gfx/geometry:geometry_skia" ]
+ },
+ {
+ types = [
+ {
+ mojom = "gfx.mojom.FrameData"
+ cpp = "::gfx::FrameData"
+ },
+ ]
+ traits_headers = [ "frame_data_mojom_traits.h" ]
traits_public_deps = [ "//ui/gfx" ]
},
]
+ if (use_blink) {
+ cpp_typemaps += [
+ {
+ types = [
+ {
+ mojom = "gfx.mojom.CALayerParams"
+ cpp = "::gfx::CALayerParams"
+ },
+ ]
+ traits_sources = [ "ca_layer_params_mojom_traits.cc" ]
+ traits_headers = [ "ca_layer_params_mojom_traits.h" ]
+ traits_public_deps = [ "//ui/gfx" ]
+ },
+ ]
+ }
+
cpp_typemaps += shared_cpp_typemaps
blink_cpp_typemaps = shared_cpp_typemaps
blink_cpp_typemaps += [
@@ -333,12 +378,20 @@
if (is_linux || is_chromeos || use_ozone) {
enabled_features = [ "supports_native_pixmap" ]
}
+ if (is_linux || is_chromeos) {
+ enabled_features += [ "is_linux_or_chromeos_ash" ]
+ }
public_deps = [ "//mojo/public/mojom/base" ]
generate_java = true
+ webui_module_path = "chrome://resources/mojo/ui/gfx/mojom"
shared_cpp_typemap = {
types = [
{
+ mojom = "gfx.mojom.DXGIHandleToken"
+ cpp = "::gfx::DXGIHandleToken"
+ },
+ {
mojom = "gfx.mojom.NativePixmapHandle"
cpp = "::gfx::NativePixmapHandle"
move_only = true
@@ -356,6 +409,16 @@
blink_cpp_typemaps = [ shared_cpp_typemap ]
}
+if (is_win) {
+ mojom("dxgi_info") {
+ sources = [ "dxgi_info.mojom" ]
+ public_deps = [
+ "//mojo/public/mojom/base",
+ "//skia/public/mojom",
+ ]
+ }
+}
+
mojom("test_interfaces") {
sources = [ "traits_test_service.mojom" ]
@@ -400,6 +463,7 @@
":native_handle_types",
"//ui/gfx",
]
+ deps = [ "//skia/public/mojom" ]
if (use_ozone) {
public_deps += [ "//ui/ozone:buildflags" ]
}
diff --git a/ui/gfx/mojom/DEPS b/ui/gfx/mojom/DEPS
index 507f9cd..4d68c95 100644
--- a/ui/gfx/mojom/DEPS
+++ b/ui/gfx/mojom/DEPS
@@ -6,4 +6,7 @@
"delegated_ink_metadata_mojom_traits\.h" : [
"+skia/public/mojom/skcolor_mojom_traits.h",
],
-}
\ No newline at end of file
+ "display_color_spaces_mojom_traits.cc" : [
+ "+skia/public/mojom/skcolorspace_primaries_mojom_traits.h",
+ ],
+}
diff --git a/ui/gfx/mojom/accelerated_widget.mojom b/ui/gfx/mojom/accelerated_widget.mojom
index 8647d67..5721880 100644
--- a/ui/gfx/mojom/accelerated_widget.mojom
+++ b/ui/gfx/mojom/accelerated_widget.mojom
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/accelerated_widget_mojom_traits.h b/ui/gfx/mojom/accelerated_widget_mojom_traits.h
index 6684590..a520636 100644
--- a/ui/gfx/mojom/accelerated_widget_mojom_traits.h
+++ b/ui/gfx/mojom/accelerated_widget_mojom_traits.h
@@ -1,10 +1,11 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_MOJOM_ACCELERATED_WIDGET_MOJOM_TRAITS_H_
#define UI_GFX_MOJOM_ACCELERATED_WIDGET_MOJOM_TRAITS_H_
+#include "base/notreached.h"
#include "build/build_config.h"
#include "ui/gfx/mojom/accelerated_widget.mojom.h"
#include "ui/gfx/native_widget_types.h"
@@ -15,9 +16,9 @@
struct StructTraits<gfx::mojom::AcceleratedWidgetDataView,
gfx::AcceleratedWidget> {
static uint64_t widget(gfx::AcceleratedWidget widget) {
-#if defined(OS_WIN) || defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
return reinterpret_cast<uint64_t>(widget);
-#elif defined(USE_OZONE) || defined(USE_X11) || defined(OS_MAC)
+#elif BUILDFLAG(IS_OZONE) || BUILDFLAG(IS_MAC)
return static_cast<uint64_t>(widget);
#else
NOTREACHED();
@@ -27,10 +28,10 @@
static bool Read(gfx::mojom::AcceleratedWidgetDataView data,
gfx::AcceleratedWidget* out) {
-#if defined(OS_WIN) || defined(OS_ANDROID) || defined(OS_IOS)
+#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
*out = reinterpret_cast<gfx::AcceleratedWidget>(data.widget());
return true;
-#elif defined(USE_OZONE) || defined(USE_X11) || defined(OS_MAC)
+#elif BUILDFLAG(IS_OZONE) || BUILDFLAG(IS_MAC)
*out = static_cast<gfx::AcceleratedWidget>(data.widget());
return true;
#else
diff --git a/ui/gfx/mojom/buffer_types.mojom b/ui/gfx/mojom/buffer_types.mojom
index 1072f73..dae4554 100644
--- a/ui/gfx/mojom/buffer_types.mojom
+++ b/ui/gfx/mojom/buffer_types.mojom
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,6 +11,7 @@
R_8,
R_16,
RG_88,
+ RG_1616,
BGR_565,
RGBA_4444,
RGBX_8888,
@@ -22,6 +23,7 @@
RGBA_F16,
YVU_420,
YUV_420_BIPLANAR,
+ YUVA_420_TRIPLANAR,
P010,
};
@@ -51,6 +53,7 @@
UV,
U,
V,
+ A,
};
// gfx::GpuMemoryBufferId
diff --git a/ui/gfx/mojom/buffer_types_mojom_traits.cc b/ui/gfx/mojom/buffer_types_mojom_traits.cc
index 9af3443..1276c76 100644
--- a/ui/gfx/mojom/buffer_types_mojom_traits.cc
+++ b/ui/gfx/mojom/buffer_types_mojom_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,7 +6,7 @@
#include "build/build_config.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/scoped_hardware_buffer_handle.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "mojo/public/cpp/system/scope_to_message_pipe.h"
@@ -33,14 +33,14 @@
return gfx::mojom::GpuMemoryBufferPlatformHandle::NewSharedMemoryHandle(
std::move(handle.region));
case gfx::NATIVE_PIXMAP:
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(USE_OZONE)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_OZONE)
return gfx::mojom::GpuMemoryBufferPlatformHandle::NewNativePixmapHandle(
std::move(handle.native_pixmap_handle));
#else
break;
#endif
case gfx::IO_SURFACE_BUFFER: {
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_APPLE)
gfx::ScopedRefCountedIOSurfaceMachPort io_surface_mach_port(
IOSurfaceCreateMachPort(handle.io_surface.get()));
return gfx::mojom::GpuMemoryBufferPlatformHandle::NewMachPort(
@@ -51,17 +51,18 @@
#endif
}
case gfx::DXGI_SHARED_HANDLE:
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
DCHECK(handle.dxgi_handle.IsValid());
+ DCHECK(handle.dxgi_token.has_value());
return gfx::mojom::GpuMemoryBufferPlatformHandle::NewDxgiHandle(
- gfx::mojom::DxgiHandle::New(
+ gfx::mojom::DXGIHandle::New(
mojo::PlatformHandle(std::move(handle.dxgi_handle)),
- std::move(handle.region)));
+ std::move(handle.dxgi_token.value()), std::move(handle.region)));
#else
break;
#endif
case gfx::ANDROID_HARDWARE_BUFFER: {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// We must keep a ref to the AHardwareBuffer alive until the receiver has
// acquired its own reference. We do this by sending a message pipe handle
// along with the buffer. When the receiver deserializes (or even if they
@@ -110,19 +111,19 @@
switch (platform_handle->which()) {
case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::
- SHARED_MEMORY_HANDLE:
+ kSharedMemoryHandle:
out->type = gfx::SHARED_MEMORY_BUFFER;
out->region = std::move(platform_handle->get_shared_memory_handle());
return true;
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(USE_OZONE)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_OZONE)
case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::
- NATIVE_PIXMAP_HANDLE:
+ kNativePixmapHandle:
out->type = gfx::NATIVE_PIXMAP;
out->native_pixmap_handle =
std::move(platform_handle->get_native_pixmap_handle());
return true;
-#elif defined(OS_MAC)
- case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::MACH_PORT: {
+#elif BUILDFLAG(IS_APPLE)
+ case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::kMachPort: {
out->type = gfx::IO_SURFACE_BUFFER;
if (!platform_handle->get_mach_port().is_mach_send())
return false;
@@ -136,17 +137,18 @@
}
return true;
}
-#elif defined(OS_WIN)
- case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::DXGI_HANDLE: {
+#elif BUILDFLAG(IS_WIN)
+ case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::kDxgiHandle: {
out->type = gfx::DXGI_SHARED_HANDLE;
auto dxgi_handle = std::move(platform_handle->get_dxgi_handle());
out->dxgi_handle = dxgi_handle->buffer_handle.TakeHandle();
+ out->dxgi_token = std::move(dxgi_handle->token);
out->region = std::move(dxgi_handle->shared_memory_handle);
return true;
}
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
case gfx::mojom::GpuMemoryBufferPlatformHandleDataView::Tag::
- ANDROID_HARDWARE_BUFFER_HANDLE: {
+ kAndroidHardwareBufferHandle: {
out->type = gfx::ANDROID_HARDWARE_BUFFER;
gfx::mojom::AHardwareBufferHandlePtr buffer_handle =
std::move(platform_handle->get_android_hardware_buffer_handle());
diff --git a/ui/gfx/mojom/buffer_types_mojom_traits.h b/ui/gfx/mojom/buffer_types_mojom_traits.h
index 5ed27e0..b5aa20b 100644
--- a/ui/gfx/mojom/buffer_types_mojom_traits.h
+++ b/ui/gfx/mojom/buffer_types_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,6 +7,7 @@
#include "base/component_export.h"
+#include "base/notreached.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/enum_traits.h"
#include "mojo/public/cpp/bindings/struct_traits.h"
@@ -28,6 +29,8 @@
return gfx::mojom::BufferFormat::R_16;
case gfx::BufferFormat::RG_88:
return gfx::mojom::BufferFormat::RG_88;
+ case gfx::BufferFormat::RG_1616:
+ return gfx::mojom::BufferFormat::RG_1616;
case gfx::BufferFormat::BGR_565:
return gfx::mojom::BufferFormat::BGR_565;
case gfx::BufferFormat::RGBA_4444:
@@ -50,6 +53,8 @@
return gfx::mojom::BufferFormat::YVU_420;
case gfx::BufferFormat::YUV_420_BIPLANAR:
return gfx::mojom::BufferFormat::YUV_420_BIPLANAR;
+ case gfx::BufferFormat::YUVA_420_TRIPLANAR:
+ return gfx::mojom::BufferFormat::YUVA_420_TRIPLANAR;
case gfx::BufferFormat::P010:
return gfx::mojom::BufferFormat::P010;
}
@@ -69,6 +74,9 @@
case gfx::mojom::BufferFormat::RG_88:
*out = gfx::BufferFormat::RG_88;
return true;
+ case gfx::mojom::BufferFormat::RG_1616:
+ *out = gfx::BufferFormat::RG_1616;
+ return true;
case gfx::mojom::BufferFormat::BGR_565:
*out = gfx::BufferFormat::BGR_565;
return true;
@@ -102,6 +110,9 @@
case gfx::mojom::BufferFormat::YUV_420_BIPLANAR:
*out = gfx::BufferFormat::YUV_420_BIPLANAR;
return true;
+ case gfx::mojom::BufferFormat::YUVA_420_TRIPLANAR:
+ *out = gfx::BufferFormat::YUVA_420_TRIPLANAR;
+ return true;
case gfx::mojom::BufferFormat::P010:
*out = gfx::BufferFormat::P010;
return true;
@@ -249,6 +260,8 @@
return gfx::mojom::BufferPlane::U;
case gfx::BufferPlane::V:
return gfx::mojom::BufferPlane::V;
+ case gfx::BufferPlane::A:
+ return gfx::mojom::BufferPlane::A;
}
NOTREACHED();
return gfx::mojom::BufferPlane::kMinValue;
@@ -271,6 +284,9 @@
case gfx::mojom::BufferPlane::V:
*out = gfx::BufferPlane::V;
return true;
+ case gfx::mojom::BufferPlane::A:
+ *out = gfx::BufferPlane::A;
+ return true;
}
NOTREACHED();
return false;
diff --git a/ui/gfx/mojom/ca_layer_params.mojom b/ui/gfx/mojom/ca_layer_params.mojom
index de00e76..1944ef5 100644
--- a/ui/gfx/mojom/ca_layer_params.mojom
+++ b/ui/gfx/mojom/ca_layer_params.mojom
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/ca_layer_params_mojom_traits.cc b/ui/gfx/mojom/ca_layer_params_mojom_traits.cc
index c1f21d7..a4296b8 100644
--- a/ui/gfx/mojom/ca_layer_params_mojom_traits.cc
+++ b/ui/gfx/mojom/ca_layer_params_mojom_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -13,7 +13,7 @@
gfx::mojom::CALayerContentPtr
StructTraits<gfx::mojom::CALayerParamsDataView, gfx::CALayerParams>::content(
const gfx::CALayerParams& ca_layer_params) {
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_APPLE)
if (ca_layer_params.io_surface_mach_port) {
DCHECK(!ca_layer_params.ca_context_id);
return gfx::mojom::CALayerContent::NewIoSurfaceMachPort(
@@ -33,11 +33,11 @@
gfx::mojom::CALayerContentDataView content_data;
data.GetContentDataView(&content_data);
switch (content_data.tag()) {
- case gfx::mojom::CALayerContentDataView::Tag::CA_CONTEXT_ID:
+ case gfx::mojom::CALayerContentDataView::Tag::kCaContextId:
out->ca_context_id = content_data.ca_context_id();
break;
- case gfx::mojom::CALayerContentDataView::Tag::IO_SURFACE_MACH_PORT:
-#if defined(OS_MAC)
+ case gfx::mojom::CALayerContentDataView::Tag::kIoSurfaceMachPort:
+#if BUILDFLAG(IS_APPLE)
mojo::PlatformHandle platform_handle =
content_data.TakeIoSurfaceMachPort();
if (!platform_handle.is_mach_send())
diff --git a/ui/gfx/mojom/ca_layer_params_mojom_traits.h b/ui/gfx/mojom/ca_layer_params_mojom_traits.h
index 4cac766..b6d3f2f 100644
--- a/ui/gfx/mojom/ca_layer_params_mojom_traits.h
+++ b/ui/gfx/mojom/ca_layer_params_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/ca_layer_result.mojom b/ui/gfx/mojom/ca_layer_result.mojom
new file mode 100644
index 0000000..56ac90e
--- /dev/null
+++ b/ui/gfx/mojom/ca_layer_result.mojom
@@ -0,0 +1,43 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module gfx.mojom;
+
+// Corresponds to gfx::CALayerResult in "ui/gfx/ca_layer_result.h"
+enum CALayerResult {
+ kCALayerSuccess = 0,
+ kCALayerFailedUnknown = 1,
+ // kCALayerFailedIOSurfaceNotCandidate = 2,
+ kCALayerFailedStreamVideoNotCandidate = 3,
+ // kCALayerFailedStreamVideoTransform = 4,
+ kCALayerFailedTextureNotCandidate = 5,
+ // kCALayerFailedTextureYFlipped = 6,
+ kCALayerFailedTileNotCandidate = 7,
+ kCALayerFailedQuadBlendMode = 8,
+ // kCALayerFailedQuadTransform = 9,
+ kCALayerFailedQuadClipping = 10,
+ kCALayerFailedDebugBoarder = 11,
+ kCALayerFailedPictureContent = 12,
+ // kCALayerFailedRenderPass = 13,
+ kCALayerFailedSurfaceContent = 14,
+ // kCALayerFailedYUVVideoContent = 15,
+ kCALayerFailedDifferentClipSettings = 16,
+ kCALayerFailedDifferentVertexOpacities = 17,
+ // kCALayerFailedRenderPassfilterScale = 18,
+ kCALayerFailedRenderPassBackdropFilters = 19,
+ kCALayerFailedRenderPassPassMask = 20,
+ kCALayerFailedRenderPassFilterOperation = 21,
+ kCALayerFailedRenderPassSortingContextId = 22,
+ kCALayerFailedTooManyRenderPassDrawQuads = 23,
+ // kCALayerFailedQuadRoundedCorner = 24,
+ // kCALayerFailedQuadRoundedCornerClipMismatch = 25,
+ kCALayerFailedQuadRoundedCornerNotUniform = 26,
+ kCALayerFailedTooManyQuads = 27,
+ kCALayerFailedYUVNotCandidate = 28,
+ kCALayerFailedYUVTexcoordMismatch = 29,
+ kCALayerFailedYUVInvalidPlanes = 30,
+ kCALayerFailedCopyRequests = 31,
+ kCALayerFailedOverlayDisabled = 32,
+ kCALayerFailedVideoCaptureEnabled = 33,
+};
diff --git a/ui/gfx/mojom/ca_layer_result_mojom_traits.cc b/ui/gfx/mojom/ca_layer_result_mojom_traits.cc
new file mode 100644
index 0000000..ed41f5d
--- /dev/null
+++ b/ui/gfx/mojom/ca_layer_result_mojom_traits.cc
@@ -0,0 +1,176 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/mojom/ca_layer_result_mojom_traits.h"
+#include "build/build_config.h"
+
+namespace mojo {
+
+#if BUILDFLAG(IS_APPLE)
+// static
+gfx::mojom::CALayerResult
+EnumTraits<gfx::mojom::CALayerResult, gfx::CALayerResult>::ToMojom(
+ gfx::CALayerResult ca_layer_error_code) {
+ switch (ca_layer_error_code) {
+ case gfx::kCALayerSuccess: // = 0,
+ return gfx::mojom::CALayerResult::kCALayerSuccess;
+ case gfx::kCALayerFailedUnknown: // = 1,
+ return gfx::mojom::CALayerResult::kCALayerFailedUnknown;
+ case gfx::kCALayerFailedStreamVideoNotCandidate: // = 3,
+ return gfx::mojom::CALayerResult::kCALayerFailedStreamVideoNotCandidate;
+ case gfx::kCALayerFailedTextureNotCandidate: // = 5,
+ return gfx::mojom::CALayerResult::kCALayerFailedTextureNotCandidate;
+ case gfx::kCALayerFailedTileNotCandidate: // = 7,
+ return gfx::mojom::CALayerResult::kCALayerFailedTileNotCandidate;
+ case gfx::kCALayerFailedQuadBlendMode: // = 8,
+ return gfx::mojom::CALayerResult::kCALayerFailedQuadBlendMode;
+ case gfx::kCALayerFailedQuadClipping: // = 10,
+ return gfx::mojom::CALayerResult::kCALayerFailedQuadClipping;
+ case gfx::kCALayerFailedDebugBoarder: // = 11,
+ return gfx::mojom::CALayerResult::kCALayerFailedDebugBoarder;
+ case gfx::kCALayerFailedPictureContent: // = 12,
+ return gfx::mojom::CALayerResult::kCALayerFailedPictureContent;
+ case gfx::kCALayerFailedSurfaceContent: // = 14,
+ return gfx::mojom::CALayerResult::kCALayerFailedSurfaceContent;
+ case gfx::kCALayerFailedDifferentClipSettings: // = 16,
+ return gfx::mojom::CALayerResult::kCALayerFailedDifferentClipSettings;
+ case gfx::kCALayerFailedDifferentVertexOpacities: // = 17,
+ return gfx::mojom::CALayerResult::kCALayerFailedDifferentVertexOpacities;
+ case gfx::kCALayerFailedRenderPassBackdropFilters: // = 19,
+ return gfx::mojom::CALayerResult::kCALayerFailedRenderPassBackdropFilters;
+ case gfx::kCALayerFailedRenderPassPassMask: // = 20,
+ return gfx::mojom::CALayerResult::kCALayerFailedRenderPassPassMask;
+ case gfx::kCALayerFailedRenderPassFilterOperation: // = 21,
+ return gfx::mojom::CALayerResult::kCALayerFailedRenderPassFilterOperation;
+ case gfx::kCALayerFailedRenderPassSortingContextId: // = 22,
+ return gfx::mojom::CALayerResult::
+ kCALayerFailedRenderPassSortingContextId;
+ case gfx::kCALayerFailedTooManyRenderPassDrawQuads: // = 23,
+ return gfx::mojom::CALayerResult::
+ kCALayerFailedTooManyRenderPassDrawQuads;
+ case gfx::kCALayerFailedQuadRoundedCornerNotUniform: // = 26,
+ return gfx::mojom::CALayerResult::
+ kCALayerFailedQuadRoundedCornerNotUniform;
+ case gfx::kCALayerFailedTooManyQuads: // = 27,
+ return gfx::mojom::CALayerResult::kCALayerFailedTooManyQuads;
+ case gfx::kCALayerFailedYUVNotCandidate: // = 28,
+ return gfx::mojom::CALayerResult::kCALayerFailedYUVNotCandidate;
+ case gfx::kCALayerFailedYUVTexcoordMismatch: // = 29,
+ return gfx::mojom::CALayerResult::kCALayerFailedYUVTexcoordMismatch;
+ case gfx::kCALayerFailedYUVInvalidPlanes: // = 30,
+ return gfx::mojom::CALayerResult::kCALayerFailedYUVInvalidPlanes;
+ case gfx::kCALayerFailedCopyRequests: // = 31,
+ return gfx::mojom::CALayerResult::kCALayerFailedCopyRequests;
+ case gfx::kCALayerFailedOverlayDisabled: // = 32,
+ return gfx::mojom::CALayerResult::kCALayerFailedOverlayDisabled;
+ case gfx::kCALayerFailedVideoCaptureEnabled: // = 33,
+ return gfx::mojom::CALayerResult::kCALayerFailedVideoCaptureEnabled;
+ case gfx::kCALayerUnknownDidNotSwap: // = 34,
+ NOTREACHED();
+ return gfx::mojom::CALayerResult::kCALayerFailedUnknown;
+ case gfx::kCALayerUnknownNoWidget: // = 35,
+ NOTREACHED();
+ return gfx::mojom::CALayerResult::kCALayerFailedUnknown;
+ }
+
+ NOTREACHED() << "CALayer result:" << ca_layer_error_code;
+ return gfx::mojom::CALayerResult::kCALayerFailedUnknown;
+}
+
+// static
+bool EnumTraits<gfx::mojom::CALayerResult, gfx::CALayerResult>::FromMojom(
+ gfx::mojom::CALayerResult input,
+ gfx::CALayerResult* out) {
+ switch (input) {
+ case gfx::mojom::CALayerResult::kCALayerSuccess: // = 0
+ *out = gfx::kCALayerSuccess;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedUnknown: // = 1
+ *out = gfx::kCALayerFailedUnknown;
+ return true;
+ case gfx::mojom::CALayerResult::
+ kCALayerFailedStreamVideoNotCandidate: // = 3
+ *out = gfx::kCALayerFailedStreamVideoNotCandidate;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedTextureNotCandidate: // = 5
+ *out = gfx::kCALayerFailedTextureNotCandidate;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedTileNotCandidate: // = 7
+ *out = gfx::kCALayerFailedTileNotCandidate;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedQuadBlendMode: // = 8
+ *out = gfx::kCALayerFailedQuadBlendMode;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedQuadClipping: // = 10
+ *out = gfx::kCALayerFailedQuadClipping;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedDebugBoarder: // = 11
+ *out = gfx::kCALayerFailedDebugBoarder;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedPictureContent: // = 12
+ *out = gfx::kCALayerFailedPictureContent;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedSurfaceContent: // = 14
+ *out = gfx::kCALayerFailedSurfaceContent;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedDifferentClipSettings: // =
+ // 16
+ *out = gfx::kCALayerFailedDifferentClipSettings;
+ return true;
+ case gfx::mojom::CALayerResult::
+ kCALayerFailedDifferentVertexOpacities: // = 17
+ *out = gfx::kCALayerFailedDifferentVertexOpacities;
+ return true;
+ case gfx::mojom::CALayerResult::
+ kCALayerFailedRenderPassBackdropFilters: // = 19
+ *out = gfx::kCALayerFailedRenderPassBackdropFilters;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedRenderPassPassMask: // = 20
+ *out = gfx::kCALayerFailedRenderPassPassMask;
+ return true;
+ case gfx::mojom::CALayerResult::
+ kCALayerFailedRenderPassFilterOperation: // = 21
+ *out = gfx::kCALayerFailedRenderPassFilterOperation;
+ return true;
+ case gfx::mojom::CALayerResult::
+ kCALayerFailedRenderPassSortingContextId: // = 22
+ *out = gfx::kCALayerFailedRenderPassSortingContextId;
+ return true;
+ case gfx::mojom::CALayerResult::
+ kCALayerFailedTooManyRenderPassDrawQuads: // = 23
+ *out = gfx::kCALayerFailedTooManyRenderPassDrawQuads;
+ return true;
+ case gfx::mojom::CALayerResult::
+ kCALayerFailedQuadRoundedCornerNotUniform: // = 26
+ *out = gfx::kCALayerFailedQuadRoundedCornerNotUniform;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedTooManyQuads: // = 27
+ *out = gfx::kCALayerFailedTooManyQuads;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedYUVNotCandidate: // = 28
+ *out = gfx::kCALayerFailedYUVNotCandidate;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedYUVTexcoordMismatch: // = 29
+ *out = gfx::kCALayerFailedYUVTexcoordMismatch;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedYUVInvalidPlanes: // = 30
+ *out = gfx::kCALayerFailedYUVInvalidPlanes;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedCopyRequests: // = 31
+ *out = gfx::kCALayerFailedCopyRequests;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedOverlayDisabled: // = 32
+ *out = gfx::kCALayerFailedOverlayDisabled;
+ return true;
+ case gfx::mojom::CALayerResult::kCALayerFailedVideoCaptureEnabled: // = 33
+ *out = gfx::kCALayerFailedVideoCaptureEnabled;
+ return true;
+ }
+
+ NOTREACHED() << "Invalid CALayer result: " << input;
+ return false;
+}
+#endif
+
+} // namespace mojo
diff --git a/ui/gfx/mojom/ca_layer_result_mojom_traits.h b/ui/gfx/mojom/ca_layer_result_mojom_traits.h
new file mode 100644
index 0000000..52eb260
--- /dev/null
+++ b/ui/gfx/mojom/ca_layer_result_mojom_traits.h
@@ -0,0 +1,29 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_MOJOM_CA_LAYER_RESULT_MOJOM_TRAITS_H_
+#define UI_GFX_MOJOM_CA_LAYER_RESULT_MOJOM_TRAITS_H_
+
+#include "build/build_config.h"
+#include "ui/gfx/ca_layer_result.h"
+
+#if BUILDFLAG(IS_APPLE)
+#include "ui/gfx/mojom/ca_layer_result.mojom-shared.h"
+#endif
+
+namespace mojo {
+
+#if BUILDFLAG(IS_APPLE)
+template <>
+struct EnumTraits<gfx::mojom::CALayerResult, gfx::CALayerResult> {
+ static gfx::mojom::CALayerResult ToMojom(
+ gfx::CALayerResult ca_layer_error_codde);
+ static bool FromMojom(gfx::mojom::CALayerResult input,
+ gfx::CALayerResult* out);
+};
+#endif
+
+} // namespace mojo
+
+#endif // UI_GFX_MOJOM_CA_LAYER_RESULT_MOJOM_TRAITS_H_
diff --git a/ui/gfx/mojom/color_space.mojom b/ui/gfx/mojom/color_space.mojom
index 1955dea..b1e132f 100644
--- a/ui/gfx/mojom/color_space.mojom
+++ b/ui/gfx/mojom/color_space.mojom
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -18,7 +18,7 @@
BT2020,
SMPTEST428_1,
SMPTEST431_2,
- SMPTEST432_1,
+ P3,
XYZ_D50,
ADOBE_RGB,
APPLE_GENERIC_RGB,
@@ -41,17 +41,18 @@
LOG_SQRT,
IEC61966_2_4,
BT1361_ECG,
- IEC61966_2_1,
+ SRGB,
BT2020_10,
BT2020_12,
- SMPTEST2084,
+ PQ,
SMPTEST428_1,
- ARIB_STD_B67,
- IEC61966_2_1_HDR,
+ HLG,
+ SRGB_HDR,
LINEAR_HDR,
CUSTOM,
CUSTOM_HDR,
- PIECEWISE_HDR
+ PIECEWISE_HDR,
+ SCRGB_LINEAR_80_NITS
};
enum ColorSpaceMatrixID {
diff --git a/ui/gfx/mojom/color_space_mojom_traits.cc b/ui/gfx/mojom/color_space_mojom_traits.cc
index 6aa83b1..cc39830 100644
--- a/ui/gfx/mojom/color_space_mojom_traits.cc
+++ b/ui/gfx/mojom/color_space_mojom_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/color_space_mojom_traits.h b/ui/gfx/mojom/color_space_mojom_traits.h
index 28943a0..c071f4e 100644
--- a/ui/gfx/mojom/color_space_mojom_traits.h
+++ b/ui/gfx/mojom/color_space_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,6 +7,7 @@
#include "base/component_export.h"
#include "base/containers/span.h"
+#include "base/notreached.h"
#include "ui/gfx/color_space.h"
#include "ui/gfx/mojom/color_space.mojom-shared.h"
@@ -37,8 +38,8 @@
return gfx::mojom::ColorSpacePrimaryID::SMPTEST428_1;
case gfx::ColorSpace::PrimaryID::SMPTEST431_2:
return gfx::mojom::ColorSpacePrimaryID::SMPTEST431_2;
- case gfx::ColorSpace::PrimaryID::SMPTEST432_1:
- return gfx::mojom::ColorSpacePrimaryID::SMPTEST432_1;
+ case gfx::ColorSpace::PrimaryID::P3:
+ return gfx::mojom::ColorSpacePrimaryID::P3;
case gfx::ColorSpace::PrimaryID::XYZ_D50:
return gfx::mojom::ColorSpacePrimaryID::XYZ_D50;
case gfx::ColorSpace::PrimaryID::ADOBE_RGB:
@@ -87,8 +88,8 @@
case gfx::mojom::ColorSpacePrimaryID::SMPTEST431_2:
*out = gfx::ColorSpace::PrimaryID::SMPTEST431_2;
return true;
- case gfx::mojom::ColorSpacePrimaryID::SMPTEST432_1:
- *out = gfx::ColorSpace::PrimaryID::SMPTEST432_1;
+ case gfx::mojom::ColorSpacePrimaryID::P3:
+ *out = gfx::ColorSpace::PrimaryID::P3;
return true;
case gfx::mojom::ColorSpacePrimaryID::XYZ_D50:
*out = gfx::ColorSpace::PrimaryID::XYZ_D50;
@@ -145,20 +146,20 @@
return gfx::mojom::ColorSpaceTransferID::IEC61966_2_4;
case gfx::ColorSpace::TransferID::BT1361_ECG:
return gfx::mojom::ColorSpaceTransferID::BT1361_ECG;
- case gfx::ColorSpace::TransferID::IEC61966_2_1:
- return gfx::mojom::ColorSpaceTransferID::IEC61966_2_1;
+ case gfx::ColorSpace::TransferID::SRGB:
+ return gfx::mojom::ColorSpaceTransferID::SRGB;
case gfx::ColorSpace::TransferID::BT2020_10:
return gfx::mojom::ColorSpaceTransferID::BT2020_10;
case gfx::ColorSpace::TransferID::BT2020_12:
return gfx::mojom::ColorSpaceTransferID::BT2020_12;
- case gfx::ColorSpace::TransferID::SMPTEST2084:
- return gfx::mojom::ColorSpaceTransferID::SMPTEST2084;
+ case gfx::ColorSpace::TransferID::PQ:
+ return gfx::mojom::ColorSpaceTransferID::PQ;
case gfx::ColorSpace::TransferID::SMPTEST428_1:
return gfx::mojom::ColorSpaceTransferID::SMPTEST428_1;
- case gfx::ColorSpace::TransferID::ARIB_STD_B67:
- return gfx::mojom::ColorSpaceTransferID::ARIB_STD_B67;
- case gfx::ColorSpace::TransferID::IEC61966_2_1_HDR:
- return gfx::mojom::ColorSpaceTransferID::IEC61966_2_1_HDR;
+ case gfx::ColorSpace::TransferID::HLG:
+ return gfx::mojom::ColorSpaceTransferID::HLG;
+ case gfx::ColorSpace::TransferID::SRGB_HDR:
+ return gfx::mojom::ColorSpaceTransferID::SRGB_HDR;
case gfx::ColorSpace::TransferID::LINEAR_HDR:
return gfx::mojom::ColorSpaceTransferID::LINEAR_HDR;
case gfx::ColorSpace::TransferID::CUSTOM:
@@ -167,6 +168,8 @@
return gfx::mojom::ColorSpaceTransferID::CUSTOM_HDR;
case gfx::ColorSpace::TransferID::PIECEWISE_HDR:
return gfx::mojom::ColorSpaceTransferID::PIECEWISE_HDR;
+ case gfx::ColorSpace::TransferID::SCRGB_LINEAR_80_NITS:
+ return gfx::mojom::ColorSpaceTransferID::SCRGB_LINEAR_80_NITS;
}
NOTREACHED();
return gfx::mojom::ColorSpaceTransferID::INVALID;
@@ -217,8 +220,8 @@
case gfx::mojom::ColorSpaceTransferID::BT1361_ECG:
*out = gfx::ColorSpace::TransferID::BT1361_ECG;
return true;
- case gfx::mojom::ColorSpaceTransferID::IEC61966_2_1:
- *out = gfx::ColorSpace::TransferID::IEC61966_2_1;
+ case gfx::mojom::ColorSpaceTransferID::SRGB:
+ *out = gfx::ColorSpace::TransferID::SRGB;
return true;
case gfx::mojom::ColorSpaceTransferID::BT2020_10:
*out = gfx::ColorSpace::TransferID::BT2020_10;
@@ -226,17 +229,17 @@
case gfx::mojom::ColorSpaceTransferID::BT2020_12:
*out = gfx::ColorSpace::TransferID::BT2020_12;
return true;
- case gfx::mojom::ColorSpaceTransferID::SMPTEST2084:
- *out = gfx::ColorSpace::TransferID::SMPTEST2084;
+ case gfx::mojom::ColorSpaceTransferID::PQ:
+ *out = gfx::ColorSpace::TransferID::PQ;
return true;
case gfx::mojom::ColorSpaceTransferID::SMPTEST428_1:
*out = gfx::ColorSpace::TransferID::SMPTEST428_1;
return true;
- case gfx::mojom::ColorSpaceTransferID::ARIB_STD_B67:
- *out = gfx::ColorSpace::TransferID::ARIB_STD_B67;
+ case gfx::mojom::ColorSpaceTransferID::HLG:
+ *out = gfx::ColorSpace::TransferID::HLG;
return true;
- case gfx::mojom::ColorSpaceTransferID::IEC61966_2_1_HDR:
- *out = gfx::ColorSpace::TransferID::IEC61966_2_1_HDR;
+ case gfx::mojom::ColorSpaceTransferID::SRGB_HDR:
+ *out = gfx::ColorSpace::TransferID::SRGB_HDR;
return true;
case gfx::mojom::ColorSpaceTransferID::LINEAR_HDR:
*out = gfx::ColorSpace::TransferID::LINEAR_HDR;
@@ -250,6 +253,9 @@
case gfx::mojom::ColorSpaceTransferID::PIECEWISE_HDR:
*out = gfx::ColorSpace::TransferID::PIECEWISE_HDR;
return true;
+ case gfx::mojom::ColorSpaceTransferID::SCRGB_LINEAR_80_NITS:
+ *out = gfx::ColorSpace::TransferID::SCRGB_LINEAR_80_NITS;
+ return true;
}
NOTREACHED();
return false;
diff --git a/ui/gfx/mojom/delegated_ink_metadata.mojom b/ui/gfx/mojom/delegated_ink_metadata.mojom
index c3b5438..06dff1b 100644
--- a/ui/gfx/mojom/delegated_ink_metadata.mojom
+++ b/ui/gfx/mojom/delegated_ink_metadata.mojom
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/delegated_ink_metadata_mojom_traits.cc b/ui/gfx/mojom/delegated_ink_metadata_mojom_traits.cc
index f3f10a8..ff86c78 100644
--- a/ui/gfx/mojom/delegated_ink_metadata_mojom_traits.cc
+++ b/ui/gfx/mojom/delegated_ink_metadata_mojom_traits.cc
@@ -1,8 +1,9 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/mojom/delegated_ink_metadata_mojom_traits.h"
+#include "base/time/time.h"
namespace mojo {
diff --git a/ui/gfx/mojom/delegated_ink_metadata_mojom_traits.h b/ui/gfx/mojom/delegated_ink_metadata_mojom_traits.h
index b9c875d..90a80ef 100644
--- a/ui/gfx/mojom/delegated_ink_metadata_mojom_traits.h
+++ b/ui/gfx/mojom/delegated_ink_metadata_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/delegated_ink_point.mojom b/ui/gfx/mojom/delegated_ink_point.mojom
index 8ed6561..8c83f8b 100644
--- a/ui/gfx/mojom/delegated_ink_point.mojom
+++ b/ui/gfx/mojom/delegated_ink_point.mojom
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/delegated_ink_point_mojom_traits.cc b/ui/gfx/mojom/delegated_ink_point_mojom_traits.cc
index 97fd785..0c16829 100644
--- a/ui/gfx/mojom/delegated_ink_point_mojom_traits.cc
+++ b/ui/gfx/mojom/delegated_ink_point_mojom_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/delegated_ink_point_mojom_traits.h b/ui/gfx/mojom/delegated_ink_point_mojom_traits.h
index b188b30..9e6de16 100644
--- a/ui/gfx/mojom/delegated_ink_point_mojom_traits.h
+++ b/ui/gfx/mojom/delegated_ink_point_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/delegated_ink_point_renderer.mojom b/ui/gfx/mojom/delegated_ink_point_renderer.mojom
index 223f343..7434bef 100644
--- a/ui/gfx/mojom/delegated_ink_point_renderer.mojom
+++ b/ui/gfx/mojom/delegated_ink_point_renderer.mojom
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/display_color_spaces.mojom b/ui/gfx/mojom/display_color_spaces.mojom
index 900e43e..00be5ae5 100644
--- a/ui/gfx/mojom/display_color_spaces.mojom
+++ b/ui/gfx/mojom/display_color_spaces.mojom
@@ -1,9 +1,10 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module gfx.mojom;
+import "skia/public/mojom/skcolorspace_primaries.mojom";
import "ui/gfx/mojom/buffer_types.mojom";
import "ui/gfx/mojom/color_space.mojom";
import "ui/gfx/mojom/hdr_static_metadata.mojom";
@@ -15,7 +16,6 @@
kHDR,
};
-
// See the typemapped class gfx::DisplayColorSpaces.
struct DisplayColorSpaces {
// The arrays of length 6 correspond to the 6 configurations in the
@@ -24,8 +24,12 @@
array<ColorSpace, 6> color_spaces;
array<BufferFormat, 6> buffer_formats;
- // The SDR white level is used to composite SDR and HDR content on Windows.
- float sdr_white_level;
+ // The primaries of the display.
+ skia.mojom.SkColorSpacePrimaries primaries;
- gfx.mojom.HDRStaticMetadata? hdr_static_metadata;
+ // The maximum SDR luminance, in nits.
+ float sdr_max_luminance_nits;
+
+ // The maximum HDR luminance, as a multiple of the SDR maximum luminance.
+ float hdr_max_luminance_relative;
};
diff --git a/ui/gfx/mojom/display_color_spaces_mojom_traits.cc b/ui/gfx/mojom/display_color_spaces_mojom_traits.cc
index 1077123..c05144d 100644
--- a/ui/gfx/mojom/display_color_spaces_mojom_traits.cc
+++ b/ui/gfx/mojom/display_color_spaces_mojom_traits.cc
@@ -1,9 +1,11 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/mojom/display_color_spaces_mojom_traits.h"
+#include "skia/public/mojom/skcolorspace_primaries_mojom_traits.h"
+
namespace mojo {
// static
@@ -68,12 +70,13 @@
if (!input.ReadColorSpaces(&color_spaces))
return false;
- out->SetSDRWhiteLevel(input.sdr_white_level());
-
- absl::optional<gfx::HDRStaticMetadata> hdr_static_metadata(
- out->hdr_static_metadata_);
- if (!input.ReadHdrStaticMetadata(&hdr_static_metadata))
+ SkColorSpacePrimaries primaries = {0.f};
+ if (!input.ReadPrimaries(&primaries))
return false;
+ out->SetPrimaries(primaries);
+
+ out->SetSDRMaxLuminanceNits(input.sdr_max_luminance_nits());
+ out->SetHDRMaxLuminanceRelative(input.hdr_max_luminance_relative());
return true;
}
diff --git a/ui/gfx/mojom/display_color_spaces_mojom_traits.h b/ui/gfx/mojom/display_color_spaces_mojom_traits.h
index 8a69547..a5901eb 100644
--- a/ui/gfx/mojom/display_color_spaces_mojom_traits.h
+++ b/ui/gfx/mojom/display_color_spaces_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,7 @@
#define UI_GFX_MOJOM_DISPLAY_COLOR_SPACES_MOJOM_TRAITS_H_
#include "base/containers/span.h"
+#include "third_party/skia/include/core/SkColorSpace.h"
#include "ui/gfx/display_color_spaces.h"
#include "ui/gfx/mojom/buffer_types_mojom_traits.h"
#include "ui/gfx/mojom/color_space_mojom_traits.h"
@@ -30,14 +31,16 @@
const gfx::DisplayColorSpaces& input);
static base::span<const gfx::BufferFormat> buffer_formats(
const gfx::DisplayColorSpaces& input);
- static float sdr_white_level(const gfx::DisplayColorSpaces& input) {
- return input.GetSDRWhiteLevel();
+ static SkColorSpacePrimaries primaries(const gfx::DisplayColorSpaces& input) {
+ return input.GetPrimaries();
}
- static const absl::optional<gfx::HDRStaticMetadata>& hdr_static_metadata(
+ static float sdr_max_luminance_nits(const gfx::DisplayColorSpaces& input) {
+ return input.GetSDRMaxLuminanceNits();
+ }
+ static float hdr_max_luminance_relative(
const gfx::DisplayColorSpaces& input) {
- return input.hdr_static_metadata();
+ return input.GetHDRMaxLuminanceRelative();
}
-
static bool Read(gfx::mojom::DisplayColorSpacesDataView data,
gfx::DisplayColorSpaces* out);
};
diff --git a/ui/gfx/mojom/dxgi_info.mojom b/ui/gfx/mojom/dxgi_info.mojom
new file mode 100644
index 0000000..31d111d
--- /dev/null
+++ b/ui/gfx/mojom/dxgi_info.mojom
@@ -0,0 +1,41 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module gfx.mojom;
+
+import "mojo/public/mojom/base/wstring.mojom";
+import "skia/public/mojom/skcolorspace_primaries.mojom";
+
+// Subset of information collected from DXGI_OUTPUT_DESC1.
+struct DXGIOutputDesc {
+ mojo_base.mojom.WString device_name;
+
+ // Set to true if the display has HDR currently enabled.
+ bool hdr_enabled;
+
+ // The color volume of the display.
+ skia.mojom.SkColorSpacePrimaries primaries;
+
+ // The minimum luminance, in nits, that the display attached to this output is
+ // capable of rendering.
+ float min_luminance;
+
+ // The maximum luminance, in nits, that the display attached to this output is
+ // capable of rendering; this value is likely only valid for a small area of
+ // the panel.
+ float max_luminance;
+
+ // The maximum luminance, in nits, that the display attached to this output is
+ // capable of rendering; unlike MaxLuminance, this value is valid for a color
+ // that fills the entire area of the panel.
+ float max_full_frame_luminance;
+};
+
+// DXGI information collected in the Gpu process and sent for use in the browser
+// process.
+struct DXGIInfo {
+ // The descriptors of all IDXGIOutputs of each IDXGIAdapters.
+ array<DXGIOutputDesc> output_descs;
+};
+
diff --git a/ui/gfx/mojom/font_render_params.mojom b/ui/gfx/mojom/font_render_params.mojom
index ac75219..9ab5533 100644
--- a/ui/gfx/mojom/font_render_params.mojom
+++ b/ui/gfx/mojom/font_render_params.mojom
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/font_render_params_mojom_traits.h b/ui/gfx/mojom/font_render_params_mojom_traits.h
index 7f2c3a3..81e60f0 100644
--- a/ui/gfx/mojom/font_render_params_mojom_traits.h
+++ b/ui/gfx/mojom/font_render_params_mojom_traits.h
@@ -1,10 +1,11 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_MOJOM_FONT_RENDER_PARAMS_MOJOM_TRAITS_H_
#define UI_GFX_MOJOM_FONT_RENDER_PARAMS_MOJOM_TRAITS_H_
+#include "base/notreached.h"
#include "ui/gfx/font_render_params.h"
#include "ui/gfx/mojom/font_render_params.mojom.h"
diff --git a/ui/gfx/mojom/frame_data.mojom b/ui/gfx/mojom/frame_data.mojom
new file mode 100644
index 0000000..d7dcfde
--- /dev/null
+++ b/ui/gfx/mojom/frame_data.mojom
@@ -0,0 +1,15 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module gfx.mojom;
+
+// This corresponds to gfx::FrameData. It contains frame specific information
+// and is passed through calls to SwapBuffers and similar.
+struct FrameData {
+ // Sequence number for this frame. The reserved value of -1 means that there
+ // is no sequence number specified (that is, corresponds to no sequence
+ // point). This may happen for some cases, like the ozone demo, tests, or
+ // users of GLSurface other than SkiaRenderer.
+ int64 seq;
+};
diff --git a/ui/gfx/mojom/frame_data_mojom_traits.h b/ui/gfx/mojom/frame_data_mojom_traits.h
new file mode 100644
index 0000000..765b7c9
--- /dev/null
+++ b/ui/gfx/mojom/frame_data_mojom_traits.h
@@ -0,0 +1,26 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_MOJOM_FRAME_DATA_MOJOM_TRAITS_H_
+#define UI_GFX_MOJOM_FRAME_DATA_MOJOM_TRAITS_H_
+
+#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "ui/gfx/frame_data.h"
+#include "ui/gfx/mojom/frame_data.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<gfx::mojom::FrameDataDataView, gfx::FrameData> {
+ static int64_t seq(const gfx::FrameData& data) { return data.seq; }
+
+ static bool Read(gfx::mojom::FrameDataDataView data, gfx::FrameData* out) {
+ out->seq = data.seq();
+ return true;
+ }
+};
+
+} // namespace mojo
+
+#endif // UI_GFX_MOJOM_FRAME_DATA_MOJOM_TRAITS_H_
diff --git a/ui/gfx/mojom/gpu_extra_info.mojom b/ui/gfx/mojom/gpu_extra_info.mojom
index 1b7b023..3de1c57 100644
--- a/ui/gfx/mojom/gpu_extra_info.mojom
+++ b/ui/gfx/mojom/gpu_extra_info.mojom
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/gpu_extra_info_mojom_traits.cc b/ui/gfx/mojom/gpu_extra_info_mojom_traits.cc
index c40726b..15c7340 100644
--- a/ui/gfx/mojom/gpu_extra_info_mojom_traits.cc
+++ b/ui/gfx/mojom/gpu_extra_info_mojom_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -24,7 +24,7 @@
gfx::GpuExtraInfo* out) {
if (!data.ReadAngleFeatures(&out->angle_features))
return false;
-#if defined(USE_OZONE_PLATFORM_X11) || defined(USE_X11)
+#if defined(USE_OZONE_PLATFORM_X11)
if (!data.ReadGpuMemoryBufferSupportX11(&out->gpu_memory_buffer_support_x11))
return false;
#endif
diff --git a/ui/gfx/mojom/gpu_extra_info_mojom_traits.h b/ui/gfx/mojom/gpu_extra_info_mojom_traits.h
index dd6b118..12b616f 100644
--- a/ui/gfx/mojom/gpu_extra_info_mojom_traits.h
+++ b/ui/gfx/mojom/gpu_extra_info_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,11 +6,12 @@
#define UI_GFX_MOJOM_GPU_EXTRA_INFO_MOJOM_TRAITS_H_
#include "base/component_export.h"
+#include "build/build_config.h"
#include "ui/gfx/gpu_extra_info.h"
#include "ui/gfx/mojom/buffer_types_mojom_traits.h"
#include "ui/gfx/mojom/gpu_extra_info.mojom-shared.h"
-#if defined(USE_OZONE)
+#if BUILDFLAG(IS_OZONE)
#include "ui/ozone/buildflags.h"
#if BUILDFLAG(OZONE_PLATFORM_X11)
#define USE_OZONE_PLATFORM_X11
@@ -61,7 +62,7 @@
return input.angle_features;
}
-#if defined(USE_OZONE_PLATFORM_X11) || defined(USE_X11)
+#if defined(USE_OZONE_PLATFORM_X11)
static const std::vector<gfx::BufferUsageAndFormat>&
gpu_memory_buffer_support_x11(const gfx::GpuExtraInfo& input) {
return input.gpu_memory_buffer_support_x11;
diff --git a/ui/gfx/mojom/gpu_fence_handle.mojom b/ui/gfx/mojom/gpu_fence_handle.mojom
index 18c8814..9193489 100644
--- a/ui/gfx/mojom/gpu_fence_handle.mojom
+++ b/ui/gfx/mojom/gpu_fence_handle.mojom
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/gpu_fence_handle_mojom_traits.cc b/ui/gfx/mojom/gpu_fence_handle_mojom_traits.cc
index 02289ca..cc38cac 100644
--- a/ui/gfx/mojom/gpu_fence_handle_mojom_traits.cc
+++ b/ui/gfx/mojom/gpu_fence_handle_mojom_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,13 +9,13 @@
namespace mojo {
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
mojo::PlatformHandle
StructTraits<gfx::mojom::GpuFenceHandleDataView,
gfx::GpuFenceHandle>::native_fd(gfx::GpuFenceHandle& handle) {
return mojo::PlatformHandle(std::move(handle.owned_fd));
}
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
mojo::PlatformHandle
StructTraits<gfx::mojom::GpuFenceHandleDataView,
gfx::GpuFenceHandle>::native_handle(gfx::GpuFenceHandle& handle) {
@@ -25,10 +25,10 @@
bool StructTraits<gfx::mojom::GpuFenceHandleDataView, gfx::GpuFenceHandle>::
Read(gfx::mojom::GpuFenceHandleDataView data, gfx::GpuFenceHandle* out) {
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
out->owned_fd = data.TakeNativeFd().TakeFD();
return true;
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
out->owned_handle = data.TakeNativeHandle().TakeHandle();
return true;
#else
@@ -38,9 +38,9 @@
void StructTraits<gfx::mojom::GpuFenceHandleDataView,
gfx::GpuFenceHandle>::SetToNull(gfx::GpuFenceHandle* handle) {
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
handle->owned_fd.reset();
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
handle->owned_handle.Close();
#endif
}
diff --git a/ui/gfx/mojom/gpu_fence_handle_mojom_traits.h b/ui/gfx/mojom/gpu_fence_handle_mojom_traits.h
index 74c04d4..9e1ae9e 100644
--- a/ui/gfx/mojom/gpu_fence_handle_mojom_traits.h
+++ b/ui/gfx/mojom/gpu_fence_handle_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -15,9 +15,9 @@
template <>
struct COMPONENT_EXPORT(GFX_SHARED_MOJOM_TRAITS)
StructTraits<gfx::mojom::GpuFenceHandleDataView, gfx::GpuFenceHandle> {
-#if defined(OS_POSIX)
+#if BUILDFLAG(IS_POSIX)
static mojo::PlatformHandle native_fd(gfx::GpuFenceHandle& handle);
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_WIN)
static mojo::PlatformHandle native_handle(gfx::GpuFenceHandle& handle);
#endif
static bool Read(gfx::mojom::GpuFenceHandleDataView data,
diff --git a/ui/gfx/mojom/hdr_metadata.mojom b/ui/gfx/mojom/hdr_metadata.mojom
index e4c8f48..8e8c205 100644
--- a/ui/gfx/mojom/hdr_metadata.mojom
+++ b/ui/gfx/mojom/hdr_metadata.mojom
@@ -1,24 +1,26 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module gfx.mojom;
-import "ui/gfx/geometry/mojom/geometry.mojom";
+import "skia/public/mojom/skcolorspace_primaries.mojom";
+
+enum HDRMode {
+ kDefault,
+ kExtended,
+};
// This defines a mojo transport format for gfx::HDRMetadata.
-// See ui/gl/hdr_metadata.h for description.
+// See ui/gfx/hdr_metadata.h for description.
struct ColorVolumeMetadata {
- gfx.mojom.PointF primary_r;
- gfx.mojom.PointF primary_g;
- gfx.mojom.PointF primary_b;
- gfx.mojom.PointF white_point;
- float luminance_max;
- float luminance_min;
- };
+ skia.mojom.SkColorSpacePrimaries primaries;
+ float luminance_max;
+ float luminance_min;
+};
struct HDRMetadata {
- ColorVolumeMetadata color_volume_metadata;
- uint32 max_content_light_level;
- uint32 max_frame_average_light_level;
- };
+ ColorVolumeMetadata color_volume_metadata;
+ uint32 max_content_light_level;
+ uint32 max_frame_average_light_level;
+};
diff --git a/ui/gfx/mojom/hdr_metadata_mojom_traits.cc b/ui/gfx/mojom/hdr_metadata_mojom_traits.cc
index 4621230..f00acbd 100644
--- a/ui/gfx/mojom/hdr_metadata_mojom_traits.cc
+++ b/ui/gfx/mojom/hdr_metadata_mojom_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -12,13 +12,7 @@
gfx::ColorVolumeMetadata* output) {
output->luminance_max = data.luminance_max();
output->luminance_min = data.luminance_min();
- if (!data.ReadPrimaryR(&output->primary_r))
- return false;
- if (!data.ReadPrimaryG(&output->primary_g))
- return false;
- if (!data.ReadPrimaryB(&output->primary_b))
- return false;
- if (!data.ReadWhitePoint(&output->white_point))
+ if (!data.ReadPrimaries(&output->primaries))
return false;
return true;
}
diff --git a/ui/gfx/mojom/hdr_metadata_mojom_traits.h b/ui/gfx/mojom/hdr_metadata_mojom_traits.h
index 5c477db..92c8690 100644
--- a/ui/gfx/mojom/hdr_metadata_mojom_traits.h
+++ b/ui/gfx/mojom/hdr_metadata_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,19 +11,38 @@
namespace mojo {
template <>
+struct EnumTraits<gfx::mojom::HDRMode, gfx::HDRMode> {
+ static gfx::mojom::HDRMode ToMojom(gfx::HDRMode input) {
+ switch (input) {
+ case gfx::HDRMode::kDefault:
+ return gfx::mojom::HDRMode::kDefault;
+ case gfx::HDRMode::kExtended:
+ return gfx::mojom::HDRMode::kExtended;
+ }
+ NOTREACHED();
+ return gfx::mojom::HDRMode::kDefault;
+ }
+
+ static bool FromMojom(gfx::mojom::HDRMode input, gfx::HDRMode* out) {
+ switch (input) {
+ case gfx::mojom::HDRMode::kDefault:
+ *out = gfx::HDRMode::kDefault;
+ return true;
+ case gfx::mojom::HDRMode::kExtended:
+ *out = gfx::HDRMode::kExtended;
+ return true;
+ }
+ NOTREACHED();
+ return false;
+ }
+};
+
+template <>
struct StructTraits<gfx::mojom::ColorVolumeMetadataDataView,
gfx::ColorVolumeMetadata> {
- static const gfx::PointF& primary_r(const gfx::ColorVolumeMetadata& input) {
- return input.primary_r;
- }
- static const gfx::PointF& primary_g(const gfx::ColorVolumeMetadata& input) {
- return input.primary_g;
- }
- static const gfx::PointF& primary_b(const gfx::ColorVolumeMetadata& input) {
- return input.primary_b;
- }
- static const gfx::PointF& white_point(const gfx::ColorVolumeMetadata& input) {
- return input.white_point;
+ static const SkColorSpacePrimaries& primaries(
+ const gfx::ColorVolumeMetadata& input) {
+ return input.primaries;
}
static float luminance_max(const gfx::ColorVolumeMetadata& input) {
return input.luminance_max;
diff --git a/ui/gfx/mojom/hdr_static_metadata.mojom b/ui/gfx/mojom/hdr_static_metadata.mojom
index fc2aad0..dd4acaf 100644
--- a/ui/gfx/mojom/hdr_static_metadata.mojom
+++ b/ui/gfx/mojom/hdr_static_metadata.mojom
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/hdr_static_metadata_mojom_traits.cc b/ui/gfx/mojom/hdr_static_metadata_mojom_traits.cc
index 86707e4..11005c7 100644
--- a/ui/gfx/mojom/hdr_static_metadata_mojom_traits.cc
+++ b/ui/gfx/mojom/hdr_static_metadata_mojom_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/hdr_static_metadata_mojom_traits.h b/ui/gfx/mojom/hdr_static_metadata_mojom_traits.h
index 411fbbb..fe259c0 100644
--- a/ui/gfx/mojom/hdr_static_metadata_mojom_traits.h
+++ b/ui/gfx/mojom/hdr_static_metadata_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/linear_gradient.mojom b/ui/gfx/mojom/linear_gradient.mojom
new file mode 100644
index 0000000..3cc6c39
--- /dev/null
+++ b/ui/gfx/mojom/linear_gradient.mojom
@@ -0,0 +1,17 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module gfx.mojom;
+
+// See ui/gfx/geometry/linear_gradient.h.
+struct Step {
+ float fraction;
+ uint8 alpha;
+};
+
+struct LinearGradient {
+ int16 angle = 0;
+ uint8 step_count = 0;
+ array<Step, 8> steps;
+};
diff --git a/ui/gfx/mojom/linear_gradient_mojom_traits.cc b/ui/gfx/mojom/linear_gradient_mojom_traits.cc
new file mode 100644
index 0000000..6b6d908
--- /dev/null
+++ b/ui/gfx/mojom/linear_gradient_mojom_traits.cc
@@ -0,0 +1,28 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/mojom/linear_gradient_mojom_traits.h"
+
+namespace mojo {
+
+// static
+bool StructTraits<gfx::mojom::LinearGradientDataView, gfx::LinearGradient>::
+ Read(gfx::mojom::LinearGradientDataView data, gfx::LinearGradient* out) {
+ std::array<gfx::LinearGradient::Step, gfx::LinearGradient::kMaxStepSize>
+ steps_data;
+ if (!data.ReadSteps(&steps_data))
+ return false;
+
+ if (data.step_count() > steps_data.size())
+ return false;
+
+ for (int i = 0; i < data.step_count(); ++i) {
+ out->AddStep(steps_data[i].fraction, steps_data[i].alpha);
+ }
+ out->set_angle(data.angle());
+
+ return true;
+}
+
+} // namespace mojo
diff --git a/ui/gfx/mojom/linear_gradient_mojom_traits.h b/ui/gfx/mojom/linear_gradient_mojom_traits.h
new file mode 100644
index 0000000..f2fd7a1
--- /dev/null
+++ b/ui/gfx/mojom/linear_gradient_mojom_traits.h
@@ -0,0 +1,52 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_MOJOM_LINEAR_GRADIENT_MOJOM_TRAITS_H_
+#define UI_GFX_MOJOM_LINEAR_GRADIENT_MOJOM_TRAITS_H_
+
+#include "ui/gfx/geometry/linear_gradient.h"
+#include "ui/gfx/mojom/linear_gradient.mojom-shared.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<gfx::mojom::StepDataView, gfx::LinearGradient::Step> {
+ static float fraction(const gfx::LinearGradient::Step& input) {
+ return input.fraction;
+ }
+
+ static uint8_t alpha(const gfx::LinearGradient::Step& input) {
+ return input.alpha;
+ }
+
+ static bool Read(gfx::mojom::StepDataView data,
+ gfx::LinearGradient::Step* out) {
+ out->fraction = data.fraction();
+ out->alpha = data.alpha();
+ return true;
+ }
+};
+
+template <>
+struct StructTraits<gfx::mojom::LinearGradientDataView, gfx::LinearGradient> {
+ static int16_t angle(const gfx::LinearGradient& input) {
+ return input.angle();
+ }
+
+ static uint8_t step_count(const gfx::LinearGradient& input) {
+ return input.step_count();
+ }
+
+ static const gfx::LinearGradient::StepArray& steps(
+ const gfx::LinearGradient& input) {
+ return input.steps();
+ }
+
+ static bool Read(gfx::mojom::LinearGradientDataView data,
+ gfx::LinearGradient* out);
+};
+
+} // namespace mojo
+
+#endif // UI_GFX_MOJOM_LINEAR_GRADIENT_MOJOM_TRAITS_H_
diff --git a/ui/gfx/mojom/mask_filter_info.mojom b/ui/gfx/mojom/mask_filter_info.mojom
index 7e3b9ea..7fbea40 100644
--- a/ui/gfx/mojom/mask_filter_info.mojom
+++ b/ui/gfx/mojom/mask_filter_info.mojom
@@ -1,12 +1,14 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module gfx.mojom;
import "ui/gfx/mojom/rrect_f.mojom";
+import "ui/gfx/mojom/linear_gradient.mojom";
-// See ui/gfx/mask_filter_info.h.
+// See ui/gfx/geometry/mask_filter_info.h.
struct MaskFilterInfo {
gfx.mojom.RRectF rounded_corner_bounds;
+ gfx.mojom.LinearGradient? gradient_mask;
};
diff --git a/ui/gfx/mojom/mask_filter_info_mojom_traits.cc b/ui/gfx/mojom/mask_filter_info_mojom_traits.cc
index 683762a..a935b59 100644
--- a/ui/gfx/mojom/mask_filter_info_mojom_traits.cc
+++ b/ui/gfx/mojom/mask_filter_info_mojom_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -12,7 +12,15 @@
gfx::RRectF bounds;
if (!data.ReadRoundedCornerBounds(&bounds))
return false;
- *out = gfx::MaskFilterInfo(bounds);
+
+ absl::optional<gfx::LinearGradient> gradient_mask;
+ if (!data.ReadGradientMask(&gradient_mask))
+ return false;
+
+ if (gradient_mask && !gradient_mask->IsEmpty())
+ *out = gfx::MaskFilterInfo(bounds, gradient_mask.value());
+ else
+ *out = gfx::MaskFilterInfo(bounds);
return true;
}
diff --git a/ui/gfx/mojom/mask_filter_info_mojom_traits.h b/ui/gfx/mojom/mask_filter_info_mojom_traits.h
index 849742a..ac94250 100644
--- a/ui/gfx/mojom/mask_filter_info_mojom_traits.h
+++ b/ui/gfx/mojom/mask_filter_info_mojom_traits.h
@@ -1,11 +1,13 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_MOJOM_MASK_FILTER_INFO_MOJOM_TRAITS_H_
#define UI_GFX_MOJOM_MASK_FILTER_INFO_MOJOM_TRAITS_H_
+#include "ui/gfx/geometry/linear_gradient.h"
#include "ui/gfx/geometry/mask_filter_info.h"
+#include "ui/gfx/mojom/linear_gradient_mojom_traits.h"
#include "ui/gfx/mojom/mask_filter_info.mojom-shared.h"
#include "ui/gfx/mojom/rrect_f_mojom_traits.h"
@@ -17,6 +19,11 @@
return info.rounded_corner_bounds();
}
+ static const absl::optional<gfx::LinearGradient>& gradient_mask(
+ const gfx::MaskFilterInfo& info) {
+ return info.gradient_mask();
+ }
+
static bool Read(gfx::mojom::MaskFilterInfoDataView data,
gfx::MaskFilterInfo* out);
};
diff --git a/ui/gfx/mojom/mojom_traits_unittest.cc b/ui/gfx/mojom/mojom_traits_unittest.cc
index c7e36bf..052a27f 100644
--- a/ui/gfx/mojom/mojom_traits_unittest.cc
+++ b/ui/gfx/mojom/mojom_traits_unittest.cc
@@ -1,9 +1,11 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <utility>
+#include "base/memory/platform_shared_memory_handle.h"
+#include "base/memory/unsafe_shared_memory_region.h"
#include "base/test/task_environment.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/receiver_set.h"
@@ -20,18 +22,40 @@
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/selection_bound.h"
+#if BUILDFLAG(IS_FUCHSIA)
+#include "base/fuchsia/koid.h"
+#endif
+
namespace gfx {
namespace {
gfx::AcceleratedWidget CastToAcceleratedWidget(int i) {
-#if defined(USE_OZONE) || defined(USE_X11) || defined(OS_APPLE)
+#if BUILDFLAG(IS_OZONE) || BUILDFLAG(IS_APPLE)
return static_cast<gfx::AcceleratedWidget>(i);
#else
return reinterpret_cast<gfx::AcceleratedWidget>(i);
#endif
}
+// Used by the GpuMemoryBufferHandle test to produce a valid object handle to
+// embed in a NativePixmapPlane object, so that the test isn't sending an
+// invalid FD/vmo object where the mojom requires a valid one.
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+base::ScopedFD CreateValidLookingBufferHandle() {
+ return base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
+ base::UnsafeSharedMemoryRegion::Create(1024))
+ .PassPlatformHandle()
+ .fd;
+}
+#elif BUILDFLAG(IS_FUCHSIA)
+zx::vmo CreateValidLookingBufferHandle() {
+ return base::UnsafeSharedMemoryRegion::TakeHandleForSerialization(
+ base::UnsafeSharedMemoryRegion::Create(1024))
+ .PassPlatformHandle();
+}
+#endif
+
class StructTraitsTest : public testing::Test, public mojom::TraitsTestService {
public:
StructTraitsTest() {}
@@ -95,45 +119,44 @@
}
TEST_F(StructTraitsTest, Transform) {
- const float col1row1 = 1.f;
- const float col2row1 = 2.f;
- const float col3row1 = 3.f;
- const float col4row1 = 4.f;
- const float col1row2 = 5.f;
- const float col2row2 = 6.f;
- const float col3row2 = 7.f;
- const float col4row2 = 8.f;
- const float col1row3 = 9.f;
- const float col2row3 = 10.f;
- const float col3row3 = 11.f;
- const float col4row3 = 12.f;
- const float col1row4 = 13.f;
- const float col2row4 = 14.f;
- const float col3row4 = 15.f;
- const float col4row4 = 16.f;
- gfx::Transform input(col1row1, col2row1, col3row1, col4row1, col1row2,
- col2row2, col3row2, col4row2, col1row3, col2row3,
- col3row3, col4row3, col1row4, col2row4, col3row4,
- col4row4);
+ const float r0c0 = 1.f;
+ const float r0c1 = 2.f;
+ const float r0c2 = 3.f;
+ const float r0c3 = 4.f;
+ const float r1c0 = 5.f;
+ const float r1c1 = 6.f;
+ const float r1c2 = 7.f;
+ const float r1c3 = 8.f;
+ const float r2c0 = 9.f;
+ const float r2c1 = 10.f;
+ const float r2c2 = 11.f;
+ const float r2c3 = 12.f;
+ const float r3c0 = 13.f;
+ const float r3c1 = 14.f;
+ const float r3c2 = 15.f;
+ const float r3c3 = 16.f;
+ auto input =
+ gfx::Transform::RowMajor(r0c0, r0c1, r0c2, r0c3, r1c0, r1c1, r1c2, r1c3,
+ r2c0, r2c1, r2c2, r2c3, r3c0, r3c1, r3c2, r3c3);
mojo::Remote<mojom::TraitsTestService> remote = GetTraitsTestRemote();
gfx::Transform output;
remote->EchoTransform(input, &output);
- EXPECT_EQ(col1row1, output.matrix().get(0, 0));
- EXPECT_EQ(col2row1, output.matrix().get(0, 1));
- EXPECT_EQ(col3row1, output.matrix().get(0, 2));
- EXPECT_EQ(col4row1, output.matrix().get(0, 3));
- EXPECT_EQ(col1row2, output.matrix().get(1, 0));
- EXPECT_EQ(col2row2, output.matrix().get(1, 1));
- EXPECT_EQ(col3row2, output.matrix().get(1, 2));
- EXPECT_EQ(col4row2, output.matrix().get(1, 3));
- EXPECT_EQ(col1row3, output.matrix().get(2, 0));
- EXPECT_EQ(col2row3, output.matrix().get(2, 1));
- EXPECT_EQ(col3row3, output.matrix().get(2, 2));
- EXPECT_EQ(col4row3, output.matrix().get(2, 3));
- EXPECT_EQ(col1row4, output.matrix().get(3, 0));
- EXPECT_EQ(col2row4, output.matrix().get(3, 1));
- EXPECT_EQ(col3row4, output.matrix().get(3, 2));
- EXPECT_EQ(col4row4, output.matrix().get(3, 3));
+ EXPECT_EQ(r0c0, output.rc(0, 0));
+ EXPECT_EQ(r0c1, output.rc(0, 1));
+ EXPECT_EQ(r0c2, output.rc(0, 2));
+ EXPECT_EQ(r0c3, output.rc(0, 3));
+ EXPECT_EQ(r1c0, output.rc(1, 0));
+ EXPECT_EQ(r1c1, output.rc(1, 1));
+ EXPECT_EQ(r1c2, output.rc(1, 2));
+ EXPECT_EQ(r1c3, output.rc(1, 3));
+ EXPECT_EQ(r2c0, output.rc(2, 0));
+ EXPECT_EQ(r2c1, output.rc(2, 1));
+ EXPECT_EQ(r2c2, output.rc(2, 2));
+ EXPECT_EQ(r2c3, output.rc(2, 3));
+ EXPECT_EQ(r3c0, output.rc(3, 0));
+ EXPECT_EQ(r3c1, output.rc(3, 1));
+ EXPECT_EQ(r3c2, output.rc(3, 2));
+ EXPECT_EQ(r3c3, output.rc(3, 3));
}
TEST_F(StructTraitsTest, AcceleratedWidget) {
@@ -147,7 +170,7 @@
TEST_F(StructTraitsTest, GpuMemoryBufferHandle) {
const gfx::GpuMemoryBufferId kId(99);
const uint32_t kOffset = 126;
- const int32_t kStride = 256;
+ const uint32_t kStride = 256;
base::UnsafeSharedMemoryRegion shared_memory_region =
base::UnsafeSharedMemoryRegion::Create(1024);
ASSERT_TRUE(shared_memory_region.IsValid());
@@ -171,21 +194,25 @@
base::UnsafeSharedMemoryRegion output_memory = std::move(output.region);
EXPECT_TRUE(output_memory.Map().IsValid());
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(USE_OZONE)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_OZONE)
gfx::GpuMemoryBufferHandle handle2;
const uint64_t kSize = kOffset + kStride;
handle2.type = gfx::NATIVE_PIXMAP;
handle2.id = kId;
handle2.offset = kOffset;
handle2.stride = kStride;
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
const uint64_t kModifier = 2;
- base::ScopedFD buffer_handle;
+ base::ScopedFD buffer_handle = CreateValidLookingBufferHandle();
handle2.native_pixmap_handle.modifier = kModifier;
-#elif defined(OS_FUCHSIA)
- zx::vmo buffer_handle;
- handle2.native_pixmap_handle.buffer_collection_id =
- gfx::SysmemBufferCollectionId::Create();
+#elif BUILDFLAG(IS_FUCHSIA)
+ zx::vmo buffer_handle = CreateValidLookingBufferHandle();
+ zx::eventpair client_handle, service_handle;
+ auto status = zx::eventpair::create(0, &client_handle, &service_handle);
+ DCHECK_EQ(status, ZX_OK);
+ zx_koid_t handle_koid = base::GetKoid(client_handle).value();
+ handle2.native_pixmap_handle.buffer_collection_handle =
+ std::move(client_handle);
handle2.native_pixmap_handle.buffer_index = 4;
handle2.native_pixmap_handle.ram_coherency = true;
#endif
@@ -193,15 +220,14 @@
std::move(buffer_handle));
remote->EchoGpuMemoryBufferHandle(std::move(handle2), &output);
EXPECT_EQ(gfx::NATIVE_PIXMAP, output.type);
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
EXPECT_EQ(kModifier, output.native_pixmap_handle.modifier);
-#elif defined(OS_FUCHSIA)
- EXPECT_EQ(handle2.native_pixmap_handle.buffer_collection_id,
- output.native_pixmap_handle.buffer_collection_id);
- EXPECT_EQ(handle2.native_pixmap_handle.buffer_index,
- output.native_pixmap_handle.buffer_index);
- EXPECT_EQ(handle2.native_pixmap_handle.ram_coherency,
- output.native_pixmap_handle.ram_coherency);
+#elif BUILDFLAG(IS_FUCHSIA)
+ EXPECT_EQ(handle_koid,
+ base::GetKoid(output.native_pixmap_handle.buffer_collection_handle)
+ .value());
+ EXPECT_EQ(4U, output.native_pixmap_handle.buffer_index);
+ EXPECT_EQ(true, output.native_pixmap_handle.ram_coherency);
#endif
ASSERT_EQ(1u, output.native_pixmap_handle.planes.size());
EXPECT_EQ(kSize, output.native_pixmap_handle.planes.back().size);
@@ -245,6 +271,10 @@
uint32_t flags =
PresentationFeedback::kVSync | PresentationFeedback::kZeroCopy;
PresentationFeedback input{timestamp, interval, flags};
+#if BUILDFLAG(IS_MAC)
+ input.ca_layer_error_code = kCALayerFailedPictureContent;
+#endif
+
input.available_timestamp = base::TimeTicks() + base::Milliseconds(20);
input.ready_timestamp = base::TimeTicks() + base::Milliseconds(21);
input.latch_timestamp = base::TimeTicks() + base::Milliseconds(22);
@@ -257,6 +287,9 @@
EXPECT_EQ(input.available_timestamp, output.available_timestamp);
EXPECT_EQ(input.ready_timestamp, output.ready_timestamp);
EXPECT_EQ(input.latch_timestamp, output.latch_timestamp);
+#if BUILDFLAG(IS_MAC)
+ EXPECT_EQ(input.ca_layer_error_code, output.ca_layer_error_code);
+#endif
}
TEST_F(StructTraitsTest, RRectF) {
diff --git a/ui/gfx/mojom/native_handle_types.mojom b/ui/gfx/mojom/native_handle_types.mojom
index e81dd83..d38d06c 100644
--- a/ui/gfx/mojom/native_handle_types.mojom
+++ b/ui/gfx/mojom/native_handle_types.mojom
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -23,13 +23,14 @@
struct NativePixmapHandle {
array<NativePixmapPlane> planes;
- [EnableIf=is_linux]
- uint64 modifier;
- [EnableIf=is_chromeos_ash]
+ [EnableIf=is_linux_or_chromeos_ash]
uint64 modifier;
+ [EnableIf=is_linux_or_chromeos_ash]
+ bool supports_zero_copy_webgpu_import;
+
[EnableIf=is_fuchsia]
- mojo_base.mojom.UnguessableToken? buffer_collection_id;
+ handle<platform> buffer_collection_handle;
[EnableIf=is_fuchsia]
uint32 buffer_index;
[EnableIf=is_fuchsia]
@@ -50,11 +51,24 @@
handle<message_pipe> tracking_pipe;
};
+// gfx::DXGIHandleToken
[EnableIf=is_win]
-struct DxgiHandle {
+struct DXGIHandleToken {
+ mojo_base.mojom.UnguessableToken value;
+};
+
+[EnableIf=is_win]
+struct DXGIHandle {
// The actual buffer windows handle.
handle<platform> buffer_handle;
+ // A unique identifier for the texture corresponding to this GMB handle. This
+ // is needed because there's no other way to uniquely identify the underlying
+ // texture. Handles get duplicated and the OS provides no other identifier.
+ // DXGISharedHandleManager in the GPU service uses this as a key to cache
+ // state across calls that reference the same texture via different handles.
+ DXGIHandleToken token;
+
// Shared memory copy of all the data. Valid only if requested by the
// consumer. It is included here because DXGI GMBs are unmappable except in
// the GPU process. So without it the consumer if a CPU readable frame is
@@ -68,11 +82,11 @@
[EnableIf=supports_native_pixmap]
NativePixmapHandle native_pixmap_handle;
- [EnableIf=is_mac]
+ [EnableIf=is_apple]
handle<platform> mach_port;
[EnableIf=is_win]
- DxgiHandle dxgi_handle;
+ DXGIHandle dxgi_handle;
[EnableIf=is_android]
AHardwareBufferHandle android_hardware_buffer_handle;
diff --git a/ui/gfx/mojom/native_handle_types_mojom_traits.cc b/ui/gfx/mojom/native_handle_types_mojom_traits.cc
index 15e5b8b..c0349e8 100644
--- a/ui/gfx/mojom/native_handle_types_mojom_traits.cc
+++ b/ui/gfx/mojom/native_handle_types_mojom_traits.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,15 +8,15 @@
namespace mojo {
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(USE_OZONE)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_OZONE)
mojo::PlatformHandle StructTraits<
gfx::mojom::NativePixmapPlaneDataView,
gfx::NativePixmapPlane>::buffer_handle(gfx::NativePixmapPlane& plane) {
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
return mojo::PlatformHandle(std::move(plane.fd));
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
return mojo::PlatformHandle(std::move(plane.vmo));
-#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
}
bool StructTraits<
@@ -28,36 +28,61 @@
out->size = data.size();
mojo::PlatformHandle handle = data.TakeBufferHandle();
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
if (!handle.is_fd())
return false;
out->fd = handle.TakeFD();
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
if (!handle.is_handle())
return false;
out->vmo = zx::vmo(handle.TakeHandle());
-#endif // defined(OS_LINUX) || defined(OS_CHROMEOS)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
return true;
}
+#if BUILDFLAG(IS_FUCHSIA)
+PlatformHandle
+StructTraits<gfx::mojom::NativePixmapHandleDataView, gfx::NativePixmapHandle>::
+ buffer_collection_handle(gfx::NativePixmapHandle& pixmap_handle) {
+ return mojo::PlatformHandle(
+ std::move(pixmap_handle.buffer_collection_handle));
+}
+#endif // BUILDFLAG(IS_FUCHSIA)
+
bool StructTraits<
gfx::mojom::NativePixmapHandleDataView,
gfx::NativePixmapHandle>::Read(gfx::mojom::NativePixmapHandleDataView data,
gfx::NativePixmapHandle* out) {
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
out->modifier = data.modifier();
+ out->supports_zero_copy_webgpu_import =
+ data.supports_zero_copy_webgpu_import();
#endif
-#if defined(OS_FUCHSIA)
- if (!data.ReadBufferCollectionId(&out->buffer_collection_id))
+#if BUILDFLAG(IS_FUCHSIA)
+ mojo::PlatformHandle handle = data.TakeBufferCollectionHandle();
+ if (!handle.is_handle())
return false;
+ out->buffer_collection_handle = zx::eventpair(handle.TakeHandle());
out->buffer_index = data.buffer_index();
out->ram_coherency = data.ram_coherency();
#endif
return data.ReadPlanes(&out->planes);
}
-#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(USE_OZONE)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_OZONE)
+
+#if BUILDFLAG(IS_WIN)
+bool StructTraits<gfx::mojom::DXGIHandleTokenDataView, gfx::DXGIHandleToken>::
+ Read(gfx::mojom::DXGIHandleTokenDataView& input,
+ gfx::DXGIHandleToken* output) {
+ base::UnguessableToken token;
+ if (!input.ReadValue(&token))
+ return false;
+ *output = gfx::DXGIHandleToken(token);
+ return true;
+}
+#endif // BUILDFLAG(IS_WIN)
} // namespace mojo
diff --git a/ui/gfx/mojom/native_handle_types_mojom_traits.h b/ui/gfx/mojom/native_handle_types_mojom_traits.h
index 43ff149..1597185 100644
--- a/ui/gfx/mojom/native_handle_types_mojom_traits.h
+++ b/ui/gfx/mojom/native_handle_types_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -15,13 +15,17 @@
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/mojom/native_handle_types.mojom-shared.h"
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(USE_OZONE)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_OZONE)
#include "ui/gfx/native_pixmap_handle.h"
#endif
+#if BUILDFLAG(IS_WIN)
+#include "ui/gfx/gpu_memory_buffer.h" // for gfx::DXGIHandleToken
+#endif
+
namespace mojo {
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(USE_OZONE)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_OZONE)
template <>
struct COMPONENT_EXPORT(GFX_NATIVE_HANDLE_TYPES_SHARED_MOJOM_TRAITS)
StructTraits<gfx::mojom::NativePixmapPlaneDataView,
@@ -49,17 +53,22 @@
return pixmap_handle.planes;
}
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
static uint64_t modifier(const gfx::NativePixmapHandle& pixmap_handle) {
return pixmap_handle.modifier;
}
#endif
-#if defined(OS_FUCHSIA)
- static const absl::optional<base::UnguessableToken>& buffer_collection_id(
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+ static bool supports_zero_copy_webgpu_import(
const gfx::NativePixmapHandle& pixmap_handle) {
- return pixmap_handle.buffer_collection_id;
+ return pixmap_handle.supports_zero_copy_webgpu_import;
}
+#endif
+
+#if BUILDFLAG(IS_FUCHSIA)
+ static PlatformHandle buffer_collection_handle(
+ gfx::NativePixmapHandle& pixmap_handle);
static uint32_t buffer_index(gfx::NativePixmapHandle& pixmap_handle) {
return pixmap_handle.buffer_index;
@@ -68,12 +77,26 @@
static bool ram_coherency(gfx::NativePixmapHandle& pixmap_handle) {
return pixmap_handle.ram_coherency;
}
-#endif // defined(OS_FUCHSIA)
+#endif // BUILDFLAG(IS_FUCHSIA)
static bool Read(gfx::mojom::NativePixmapHandleDataView data,
gfx::NativePixmapHandle* out);
};
-#endif // defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(USE_OZONE)
+#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_OZONE)
+
+#if BUILDFLAG(IS_WIN)
+template <>
+struct COMPONENT_EXPORT(GFX_NATIVE_HANDLE_TYPES_SHARED_MOJOM_TRAITS)
+ StructTraits<gfx::mojom::DXGIHandleTokenDataView, gfx::DXGIHandleToken> {
+ static const base::UnguessableToken& value(
+ const gfx::DXGIHandleToken& input) {
+ return input.value();
+ }
+
+ static bool Read(gfx::mojom::DXGIHandleTokenDataView& input,
+ gfx::DXGIHandleToken* output);
+};
+#endif // BUILDFLAG(IS_WIN)
} // namespace mojo
diff --git a/ui/gfx/mojom/overlay_priority_hint.mojom b/ui/gfx/mojom/overlay_priority_hint.mojom
index 9e976af..4477597 100644
--- a/ui/gfx/mojom/overlay_priority_hint.mojom
+++ b/ui/gfx/mojom/overlay_priority_hint.mojom
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,4 +10,5 @@
kRegular,
kLowLatencyCanvas,
kHardwareProtection,
+ kVideo,
};
diff --git a/ui/gfx/mojom/overlay_priority_hint_mojom_traits.h b/ui/gfx/mojom/overlay_priority_hint_mojom_traits.h
index ea950ec..c4e7a3b 100644
--- a/ui/gfx/mojom/overlay_priority_hint_mojom_traits.h
+++ b/ui/gfx/mojom/overlay_priority_hint_mojom_traits.h
@@ -1,10 +1,11 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_MOJOM_OVERLAY_PRIORITY_HINT_MOJOM_TRAITS_H_
#define UI_GFX_MOJOM_OVERLAY_PRIORITY_HINT_MOJOM_TRAITS_H_
+#include "base/notreached.h"
#include "ui/gfx/mojom/overlay_priority_hint.mojom.h"
#include "ui/gfx/overlay_priority_hint.h"
@@ -23,6 +24,8 @@
return gfx::mojom::OverlayPriorityHint::kLowLatencyCanvas;
case gfx::OverlayPriorityHint::kHardwareProtection:
return gfx::mojom::OverlayPriorityHint::kHardwareProtection;
+ case gfx::OverlayPriorityHint::kVideo:
+ return gfx::mojom::OverlayPriorityHint::kVideo;
}
NOTREACHED();
return gfx::mojom::OverlayPriorityHint::kNone;
@@ -43,6 +46,9 @@
case gfx::mojom::OverlayPriorityHint::kHardwareProtection:
*out = gfx::OverlayPriorityHint::kHardwareProtection;
return true;
+ case gfx::mojom::OverlayPriorityHint::kVideo:
+ *out = gfx::OverlayPriorityHint::kVideo;
+ return true;
}
NOTREACHED();
return false;
diff --git a/ui/gfx/mojom/overlay_transform.mojom b/ui/gfx/mojom/overlay_transform.mojom
index af64e36..6021528 100644
--- a/ui/gfx/mojom/overlay_transform.mojom
+++ b/ui/gfx/mojom/overlay_transform.mojom
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/overlay_transform_mojom_traits.h b/ui/gfx/mojom/overlay_transform_mojom_traits.h
index b94c5f1..62c028e 100644
--- a/ui/gfx/mojom/overlay_transform_mojom_traits.h
+++ b/ui/gfx/mojom/overlay_transform_mojom_traits.h
@@ -1,10 +1,11 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_MOJOM_OVERLAY_TRANSFORM_MOJOM_TRAITS_H_
#define UI_GFX_MOJOM_OVERLAY_TRANSFORM_MOJOM_TRAITS_H_
+#include "base/notreached.h"
#include "ui/gfx/mojom/overlay_transform.mojom.h"
#include "ui/gfx/overlay_transform.h"
diff --git a/ui/gfx/mojom/presentation_feedback.mojom b/ui/gfx/mojom/presentation_feedback.mojom
index 2ddc661..a91727b 100644
--- a/ui/gfx/mojom/presentation_feedback.mojom
+++ b/ui/gfx/mojom/presentation_feedback.mojom
@@ -1,10 +1,12 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module gfx.mojom;
import "mojo/public/mojom/base/time.mojom";
+[EnableIf=is_apple]
+import "ui/gfx/mojom/ca_layer_result.mojom";
// gfx::PresentationFeedback
struct PresentationFeedback {
@@ -16,4 +18,6 @@
mojo_base.mojom.TimeTicks ready_timestamp;
mojo_base.mojom.TimeTicks latch_timestamp;
mojo_base.mojom.TimeTicks writes_done_timestamp;
+[EnableIf=is_apple]
+ CALayerResult ca_layer_error_code;
};
diff --git a/ui/gfx/mojom/presentation_feedback_mojom_traits.h b/ui/gfx/mojom/presentation_feedback_mojom_traits.h
index bee9e78..25b04ab 100644
--- a/ui/gfx/mojom/presentation_feedback_mojom_traits.h
+++ b/ui/gfx/mojom/presentation_feedback_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,10 +6,16 @@
#define UI_GFX_MOJOM_PRESENTATION_FEEDBACK_MOJOM_TRAITS_H_
#include "base/time/time.h"
+#include "build/build_config.h"
#include "mojo/public/cpp/base/time_mojom_traits.h"
+#include "ui/gfx/ca_layer_result.h"
#include "ui/gfx/mojom/presentation_feedback.mojom-shared.h"
#include "ui/gfx/presentation_feedback.h"
+#if BUILDFLAG(IS_APPLE)
+#include "ui/gfx/mojom/ca_layer_result_mojom_traits.h"
+#endif
+
namespace mojo {
template <>
@@ -47,6 +53,13 @@
return input.writes_done_timestamp;
}
+#if BUILDFLAG(IS_APPLE)
+ static gfx::CALayerResult ca_layer_error_code(
+ const gfx::PresentationFeedback& input) {
+ return input.ca_layer_error_code;
+ }
+#endif
+
static bool Read(gfx::mojom::PresentationFeedbackDataView data,
gfx::PresentationFeedback* out) {
out->flags = data.flags();
@@ -55,6 +68,9 @@
data.ReadAvailableTimestamp(&out->available_timestamp) &&
data.ReadReadyTimestamp(&out->ready_timestamp) &&
data.ReadLatchTimestamp(&out->latch_timestamp) &&
+#if BUILDFLAG(IS_APPLE)
+ data.ReadCaLayerErrorCode(&out->ca_layer_error_code) &&
+#endif
data.ReadWritesDoneTimestamp(&out->writes_done_timestamp);
}
};
diff --git a/ui/gfx/mojom/rrect_f.mojom b/ui/gfx/mojom/rrect_f.mojom
index c10e8f4..3a3b364 100644
--- a/ui/gfx/mojom/rrect_f.mojom
+++ b/ui/gfx/mojom/rrect_f.mojom
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/rrect_f_mojom_traits.h b/ui/gfx/mojom/rrect_f_mojom_traits.h
index 1e73285..bbff7d5 100644
--- a/ui/gfx/mojom/rrect_f_mojom_traits.h
+++ b/ui/gfx/mojom/rrect_f_mojom_traits.h
@@ -1,10 +1,11 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_MOJOM_RRECT_F_MOJOM_TRAITS_H_
#define UI_GFX_MOJOM_RRECT_F_MOJOM_TRAITS_H_
+#include "base/notreached.h"
#include "ui/gfx/geometry/mojom/geometry_mojom_traits.h"
#include "ui/gfx/geometry/rrect_f.h"
#include "ui/gfx/geometry/rrect_f_builder.h"
diff --git a/ui/gfx/mojom/selection_bound.mojom b/ui/gfx/mojom/selection_bound.mojom
index 55b56c1..35f8709 100644
--- a/ui/gfx/mojom/selection_bound.mojom
+++ b/ui/gfx/mojom/selection_bound.mojom
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/selection_bound_mojom_traits.h b/ui/gfx/mojom/selection_bound_mojom_traits.h
index e001ae5..5555897 100644
--- a/ui/gfx/mojom/selection_bound_mojom_traits.h
+++ b/ui/gfx/mojom/selection_bound_mojom_traits.h
@@ -1,10 +1,11 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_MOJOM_SELECTION_BOUND_MOJOM_TRAITS_H_
#define UI_GFX_MOJOM_SELECTION_BOUND_MOJOM_TRAITS_H_
+#include "base/notreached.h"
#include "ui/gfx/geometry/mojom/geometry_mojom_traits.h"
#include "ui/gfx/mojom/selection_bound.mojom-shared.h"
#include "ui/gfx/selection_bound.h"
diff --git a/ui/gfx/mojom/swap_result.mojom b/ui/gfx/mojom/swap_result.mojom
index f206fee..3dde836 100644
--- a/ui/gfx/mojom/swap_result.mojom
+++ b/ui/gfx/mojom/swap_result.mojom
@@ -1,4 +1,4 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/swap_result_mojom_traits.h b/ui/gfx/mojom/swap_result_mojom_traits.h
index 245a5a3..ddad1e8 100644
--- a/ui/gfx/mojom/swap_result_mojom_traits.h
+++ b/ui/gfx/mojom/swap_result_mojom_traits.h
@@ -1,10 +1,11 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_MOJOM_SWAP_RESULT_MOJOM_TRAITS_H_
#define UI_GFX_MOJOM_SWAP_RESULT_MOJOM_TRAITS_H_
+#include "base/notreached.h"
#include "mojo/public/cpp/bindings/enum_traits.h"
#include "ui/gfx/mojom/swap_result.mojom-shared.h"
#include "ui/gfx/swap_result.h"
diff --git a/ui/gfx/mojom/swap_timings.mojom b/ui/gfx/mojom/swap_timings.mojom
index af51a0b..a8ab6fe 100644
--- a/ui/gfx/mojom/swap_timings.mojom
+++ b/ui/gfx/mojom/swap_timings.mojom
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/swap_timings_mojom_traits.h b/ui/gfx/mojom/swap_timings_mojom_traits.h
index 96ea989..63d1c41 100644
--- a/ui/gfx/mojom/swap_timings_mojom_traits.h
+++ b/ui/gfx/mojom/swap_timings_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/traits_test_service.mojom b/ui/gfx/mojom/traits_test_service.mojom
index 7cdcb7f..0648964 100644
--- a/ui/gfx/mojom/traits_test_service.mojom
+++ b/ui/gfx/mojom/traits_test_service.mojom
@@ -1,10 +1,9 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module gfx.mojom;
-import "ui/gfx/mojom/accelerated_widget.mojom";
import "ui/gfx/mojom/buffer_types.mojom";
import "ui/gfx/mojom/rrect_f.mojom";
import "ui/gfx/mojom/selection_bound.mojom";
diff --git a/ui/gfx/mojom/transform.mojom b/ui/gfx/mojom/transform.mojom
index badc081..f4d2ab1 100644
--- a/ui/gfx/mojom/transform.mojom
+++ b/ui/gfx/mojom/transform.mojom
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/mojom/transform_mojom_traits.h b/ui/gfx/mojom/transform_mojom_traits.h
index b8c3887..6a3229b 100644
--- a/ui/gfx/mojom/transform_mojom_traits.h
+++ b/ui/gfx/mojom/transform_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -12,23 +12,14 @@
namespace mojo {
template <>
-struct ArrayTraits<skia::Matrix44> {
- using Element = float;
-
- static bool IsNull(const skia::Matrix44& input) { return input.isIdentity(); }
-
- static size_t GetSize(const skia::Matrix44& input) { return 16; }
-
- static float GetAt(const skia::Matrix44& input, size_t index) {
- return input.getFloat(static_cast<int>(index % 4),
- static_cast<int>(index / 4));
- }
-};
-
-template <>
struct StructTraits<gfx::mojom::TransformDataView, gfx::Transform> {
- static const skia::Matrix44& matrix(const gfx::Transform& transform) {
- return transform.matrix();
+ static absl::optional<std::array<float, 16>> matrix(
+ const gfx::Transform& transform) {
+ if (transform.IsIdentity())
+ return absl::nullopt;
+ std::array<float, 16> matrix;
+ transform.GetColMajorF(matrix.data());
+ return matrix;
}
static bool Read(gfx::mojom::TransformDataView data, gfx::Transform* out) {
@@ -38,7 +29,7 @@
out->MakeIdentity();
return true;
}
- out->matrix().setColMajorf(matrix.data());
+ *out = gfx::Transform::ColMajorF(matrix.data());
return true;
}
};
diff --git a/ui/gfx/native_pixmap.h b/ui/gfx/native_pixmap.h
index c90af23..92efc95 100644
--- a/ui/gfx/native_pixmap.h
+++ b/ui/gfx/native_pixmap.h
@@ -1,12 +1,10 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_NATIVE_PIXMAP_H_
#define UI_GFX_NATIVE_PIXMAP_H_
-#include "base/bind.h"
-#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "ui/gfx/buffer_types.h"
#include "ui/gfx/geometry/size.h"
@@ -33,6 +31,7 @@
virtual size_t GetDmaBufPlaneSize(size_t plane) const = 0;
// Return the number of non-interleaved "color" planes.
virtual size_t GetNumberOfPlanes() const = 0;
+ virtual bool SupportsZeroCopyWebGPUImport() const = 0;
// The following methods return format, modifier and size of the buffer,
// respectively.
diff --git a/ui/gfx/native_pixmap_handle.cc b/ui/gfx/native_pixmap_handle.cc
index 137056b..a27f45b 100644
--- a/ui/gfx/native_pixmap_handle.cc
+++ b/ui/gfx/native_pixmap_handle.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,20 +8,24 @@
#include "base/logging.h"
#include "build/build_config.h"
+#include "ui/gfx/buffer_format_util.h"
+#include "ui/gfx/geometry/size.h"
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include <drm_fourcc.h>
+#include <unistd.h>
+
#include "base/posix/eintr_wrapper.h"
#endif
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
#include <lib/zx/vmo.h>
#include "base/fuchsia/fuchsia_logging.h"
#endif
namespace gfx {
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
static_assert(NativePixmapHandle::kNoModifier == DRM_FORMAT_MOD_INVALID,
"gfx::NativePixmapHandle::kNoModifier should be an alias for"
"DRM_FORMAT_MOD_INVALID");
@@ -32,10 +36,10 @@
NativePixmapPlane::NativePixmapPlane(int stride,
int offset,
uint64_t size
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
,
base::ScopedFD fd
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
,
zx::vmo vmo
#endif
@@ -43,10 +47,10 @@
: stride(stride),
offset(offset),
size(size)
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
,
fd(std::move(fd))
-#elif defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_FUCHSIA)
,
vmo(std::move(vmo))
#endif
@@ -71,16 +75,24 @@
NativePixmapHandle CloneHandleForIPC(const NativePixmapHandle& handle) {
NativePixmapHandle clone;
for (auto& plane : handle.planes) {
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
DCHECK(plane.fd.is_valid());
- base::ScopedFD fd_dup(HANDLE_EINTR(dup(plane.fd.get())));
+ // Combining the HANDLE_EINTR and ScopedFD's constructor causes the compiler
+ // to emit some very strange assembly that tends to cause FD ownership
+ // violations. see crbug.com/c/1287325.
+ int checked_dup = HANDLE_EINTR(dup(plane.fd.get()));
+ base::ScopedFD fd_dup(checked_dup);
if (!fd_dup.is_valid()) {
PLOG(ERROR) << "dup";
return NativePixmapHandle();
}
- clone.planes.emplace_back(plane.stride, plane.offset, plane.size,
- std::move(fd_dup));
-#elif defined(OS_FUCHSIA)
+ NativePixmapPlane cloned_plane;
+ cloned_plane.stride = plane.stride;
+ cloned_plane.offset = plane.offset;
+ cloned_plane.size = plane.size;
+ cloned_plane.fd = std::move(fd_dup);
+ clone.planes.push_back(std::move(cloned_plane));
+#elif BUILDFLAG(IS_FUCHSIA)
zx::vmo vmo_dup;
// VMO may be set to NULL for pixmaps that cannot be mapped.
if (plane.vmo) {
@@ -90,19 +102,32 @@
return NativePixmapHandle();
}
}
- clone.planes.emplace_back(plane.stride, plane.offset, plane.size,
- std::move(vmo_dup));
+ NativePixmapPlane cloned_plane;
+ cloned_plane.stride = plane.stride;
+ cloned_plane.offset = plane.offset;
+ cloned_plane.size = plane.size;
+ cloned_plane.vmo = std::move(vmo_dup);
+ clone.planes.push_back(std::move(cloned_plane));
#else
#error Unsupported OS
#endif
}
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
clone.modifier = handle.modifier;
+ clone.supports_zero_copy_webgpu_import =
+ handle.supports_zero_copy_webgpu_import;
#endif
-#if defined(OS_FUCHSIA)
- clone.buffer_collection_id = handle.buffer_collection_id;
+#if BUILDFLAG(IS_FUCHSIA)
+ if (handle.buffer_collection_handle) {
+ zx_status_t status = handle.buffer_collection_handle.duplicate(
+ ZX_RIGHT_SAME_RIGHTS, &clone.buffer_collection_handle);
+ if (status != ZX_OK) {
+ ZX_DLOG(ERROR, status) << "zx_handle_duplicate";
+ return NativePixmapHandle();
+ }
+ }
clone.buffer_index = handle.buffer_index;
clone.ram_coherency = handle.ram_coherency;
#endif
@@ -110,4 +135,73 @@
return clone;
}
+bool CanFitImageForSizeAndFormat(const gfx::NativePixmapHandle& handle,
+ const gfx::Size& size,
+ gfx::BufferFormat format,
+ bool assume_single_memory_object) {
+ size_t expected_planes = gfx::NumberOfPlanesForLinearBufferFormat(format);
+ if (expected_planes == 0 || handle.planes.size() != expected_planes)
+ return false;
+
+ size_t total_size = 0u;
+ if (assume_single_memory_object) {
+ if (!base::IsValueInRangeForNumericType<size_t>(
+ handle.planes.back().offset) ||
+ !base::IsValueInRangeForNumericType<size_t>(
+ handle.planes.back().size)) {
+ return false;
+ }
+ const base::CheckedNumeric<size_t> total_size_checked =
+ base::CheckAdd(base::checked_cast<size_t>(handle.planes.back().offset),
+ base::checked_cast<size_t>(handle.planes.back().size));
+ if (!total_size_checked.IsValid())
+ return false;
+ total_size = total_size_checked.ValueOrDie();
+ }
+
+ for (size_t i = 0; i < handle.planes.size(); ++i) {
+ const size_t plane_stride =
+ base::strict_cast<size_t>(handle.planes[i].stride);
+ size_t min_stride = 0;
+ if (!gfx::RowSizeForBufferFormatChecked(
+ base::checked_cast<size_t>(size.width()), format, i, &min_stride) ||
+ plane_stride < min_stride) {
+ return false;
+ }
+
+ const size_t subsample_factor = SubsamplingFactorForBufferFormat(format, i);
+ const base::CheckedNumeric<size_t> plane_height =
+ base::CheckDiv(base::CheckAdd(base::checked_cast<size_t>(size.height()),
+ base::CheckSub(subsample_factor, 1)),
+ subsample_factor);
+ const base::CheckedNumeric<size_t> min_size = plane_height * plane_stride;
+ if (!min_size.IsValid<uint64_t>() ||
+ handle.planes[i].size < min_size.ValueOrDie<uint64_t>()) {
+ return false;
+ }
+
+ // The stride must be a valid integer in order to be consistent with the
+ // GpuMemoryBuffer::stride()/gfx::ClientNativePixmap::GetStride() APIs.
+ // Also, refer to http://crbug.com/1093644#c1 for some comments on this
+ // check and others in this method.
+ if (!base::IsValueInRangeForNumericType<int>(plane_stride))
+ return false;
+
+ if (assume_single_memory_object) {
+ if (!base::IsValueInRangeForNumericType<size_t>(
+ handle.planes[i].offset) ||
+ !base::IsValueInRangeForNumericType<size_t>(handle.planes[i].size)) {
+ return false;
+ }
+ base::CheckedNumeric<size_t> end_pos =
+ base::CheckAdd(base::checked_cast<size_t>(handle.planes[i].offset),
+ base::checked_cast<size_t>(handle.planes[i].size));
+ if (!end_pos.IsValid() || end_pos.ValueOrDie() > total_size)
+ return false;
+ }
+ }
+
+ return true;
+}
+
} // namespace gfx
diff --git a/ui/gfx/native_pixmap_handle.h b/ui/gfx/native_pixmap_handle.h
index d0d769b..9da783a 100644
--- a/ui/gfx/native_pixmap_handle.h
+++ b/ui/gfx/native_pixmap_handle.h
@@ -1,20 +1,137 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_NATIVE_PIXMAP_HANDLE_H_
#define UI_GFX_NATIVE_PIXMAP_HANDLE_H_
-// A reduced version of `native_pixmap_handle.h` enough to make required files
-// in Chromium media to be built.
+#include <stddef.h>
+#include <stdint.h>
+
+#include <vector>
+
+#include "build/build_config.h"
+#include "ui/gfx/buffer_types.h"
+#include "ui/gfx/gfx_export.h"
+
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#include "base/files/scoped_file.h"
+#endif
+
+#if BUILDFLAG(IS_FUCHSIA)
+#include <lib/zx/eventpair.h>
+#include <lib/zx/vmo.h>
+#endif
namespace gfx {
-class NativePixmapHandle {
- public:
- static constexpr uint64_t kNoModifier = 0x00ffffffffffffff;
+class Size;
+
+// NativePixmapPlane is used to carry the plane related information for GBM
+// buffer. More fields can be added if they are plane specific.
+struct GFX_EXPORT NativePixmapPlane {
+ NativePixmapPlane();
+ NativePixmapPlane(int stride,
+ int offset,
+ uint64_t size
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+ ,
+ base::ScopedFD fd
+#elif BUILDFLAG(IS_FUCHSIA)
+ ,
+ zx::vmo vmo
+#endif
+ );
+ NativePixmapPlane(NativePixmapPlane&& other);
+ ~NativePixmapPlane();
+
+ NativePixmapPlane& operator=(NativePixmapPlane&& other);
+
+ // The strides and offsets in bytes to be used when accessing the buffers via
+ // a memory mapping. One per plane per entry.
+ uint32_t stride;
+ uint64_t offset;
+ // Size in bytes of the plane.
+ // This is necessary to map the buffers.
+ uint64_t size;
+
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+ // File descriptor for the underlying memory object (usually dmabuf).
+ base::ScopedFD fd;
+#elif BUILDFLAG(IS_FUCHSIA)
+ zx::vmo vmo;
+#endif
};
+struct GFX_EXPORT NativePixmapHandle {
+ // This is the same value as DRM_FORMAT_MOD_INVALID, which is not a valid
+ // modifier. We use this to indicate that layout information
+ // (tiling/compression) if any will be communicated out of band.
+ static constexpr uint64_t kNoModifier = 0x00ffffffffffffffULL;
+
+ NativePixmapHandle();
+ NativePixmapHandle(NativePixmapHandle&& other);
+
+ ~NativePixmapHandle();
+
+ NativePixmapHandle& operator=(NativePixmapHandle&& other);
+
+ std::vector<NativePixmapPlane> planes;
+
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+ // The modifier is retrieved from GBM library and passed to EGL driver.
+ // Generally it's platform specific, and we don't need to modify it in
+ // Chromium code. Also one per plane per entry.
+ uint64_t modifier = kNoModifier;
+
+ // WebGPU can directly import the handle to create texture from it.
+ bool supports_zero_copy_webgpu_import = false;
+#endif
+
+#if BUILDFLAG(IS_FUCHSIA)
+ // Sysmem buffer collection handle. The other end of the eventpair is owned
+ // by the SysmemBufferCollection instance in the GPU process. It will destroy
+ // itself when all handles for the collection are dropped. Eventpair is used
+ // here because they are dupable, nun-fungible and unique.
+ zx::eventpair buffer_collection_handle;
+ uint32_t buffer_index = 0;
+
+ // Set to true for sysmem buffers which are initialized with RAM coherency
+ // domain. This means that clients that write to the buffers must flush CPU
+ // cache.
+ bool ram_coherency = false;
+#endif
+};
+
+// Returns an instance of |handle| which can be sent over IPC. This duplicates
+// the file-handles, so that the IPC code take ownership of them, without
+// invalidating |handle|.
+GFX_EXPORT NativePixmapHandle
+CloneHandleForIPC(const NativePixmapHandle& handle);
+
+// Returns true iff the plane metadata (number of planes, plane size, offset,
+// and stride) in |handle| corresponds to a buffer that can store an image of
+// |size| and |format|. This function does not check the plane handles, so even
+// if this function returns true, it's not guaranteed that the memory objects
+// referenced by |handle| are consistent with the plane metadata. If
+// |assume_single_memory_object| is true, this function assumes that all planes
+// in |handle| reference the same memory object and that all planes are
+// contained in the range [0, last plane's offset + last plane's size) (and the
+// plane metadata is validated against this assumption).
+//
+// If this function returns true, the caller may make the following additional
+// assumptions:
+//
+// - The stride of each plane can fit in an int (and also in a size_t).
+// - If |assume_single_memory_object| is true:
+// - The offset and size of each plane can fit in a size_t.
+// - The result of offset + size for each plane does not overflow and can fit
+// in a size_t.
+GFX_EXPORT bool CanFitImageForSizeAndFormat(
+ const gfx::NativePixmapHandle& handle,
+ const gfx::Size& size,
+ gfx::BufferFormat format,
+ bool assume_single_memory_object);
} // namespace gfx
#endif // UI_GFX_NATIVE_PIXMAP_HANDLE_H_
diff --git a/ui/gfx/native_widget_types.h b/ui/gfx/native_widget_types.h
index 334d61f..46a02a3 100644
--- a/ui/gfx/native_widget_types.h
+++ b/ui/gfx/native_widget_types.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,11 +11,11 @@
#include "build/chromeos_buildflags.h"
#include "ui/gfx/gfx_export.h"
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/scoped_java_ref.h"
-#elif defined(OS_APPLE)
-#include <objc/objc.h>
-#elif defined(OS_WIN)
+#elif BUILDFLAG(IS_MAC)
+#include <string>
+#elif BUILDFLAG(IS_WIN)
#include "base/win/windows_types.h"
#endif
@@ -36,7 +36,7 @@
// unless you're in the IPC layer, which will be translating between
// NativeViewIds from the renderer and NativeViews.
//
-// The name 'View' here meshes with OS X where the UI elements are called
+// The name 'View' here meshes with macOS where the UI elements are called
// 'views' and with our Chrome UI code where the elements are also called
// 'views'.
@@ -54,48 +54,43 @@
#endif // defined(USE_AURA)
-#if defined(OS_WIN)
-typedef struct HFONT__* HFONT;
+#if BUILDFLAG(IS_WIN)
struct IAccessible;
-#elif defined(OS_IOS)
-struct CGContext;
+#elif BUILDFLAG(IS_IOS)
#ifdef __OBJC__
+struct objc_object;
@class UIEvent;
-@class UIFont;
@class UIImage;
@class UIView;
@class UIWindow;
@class UITextField;
#else
class UIEvent;
-class UIFont;
class UIImage;
class UIView;
class UIWindow;
class UITextField;
#endif // __OBJC__
-#elif defined(OS_MAC)
-struct CGContext;
+#elif BUILDFLAG(IS_MAC)
#ifdef __OBJC__
@class NSCursor;
@class NSEvent;
-@class NSFont;
@class NSImage;
@class NSView;
@class NSWindow;
@class NSTextField;
#else
+struct objc_object;
class NSCursor;
class NSEvent;
-class NSFont;
class NSImage;
-struct NSView;
+class NSView;
class NSWindow;
class NSTextField;
#endif // __OBJC__
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
struct ANativeWindow;
namespace ui {
class WindowAndroid;
@@ -106,48 +101,49 @@
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#if defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
extern "C" {
struct _AtkObject;
-typedef struct _AtkObject AtkObject;
+using AtkObject = struct _AtkObject;
}
#endif
namespace gfx {
#if defined(USE_AURA)
-typedef ui::Cursor NativeCursor;
-typedef aura::Window* NativeView;
-typedef aura::Window* NativeWindow;
-typedef ui::Event* NativeEvent;
+using NativeCursor = ui::Cursor;
+using NativeView = aura::Window*;
+using NativeWindow = aura::Window*;
+using NativeEvent = ui::Event*;
constexpr NativeView kNullNativeView = nullptr;
constexpr NativeWindow kNullNativeWindow = nullptr;
-#elif defined(OS_IOS)
-typedef void* NativeCursor;
-typedef UIView* NativeView;
-typedef UIWindow* NativeWindow;
-typedef UIEvent* NativeEvent;
+#elif BUILDFLAG(IS_IOS)
+using NativeCursor = void*;
+using NativeView = UIView*;
+using NativeWindow = UIWindow*;
+using NativeEvent = UIEvent*;
constexpr NativeView kNullNativeView = nullptr;
constexpr NativeWindow kNullNativeWindow = nullptr;
-#elif defined(OS_MAC)
-typedef NSCursor* NativeCursor;
-typedef NSEvent* NativeEvent;
+#elif BUILDFLAG(IS_MAC)
+using NativeCursor = NSCursor*;
+using NativeEvent = NSEvent*;
// NativeViews and NativeWindows on macOS are not necessarily in the same
-// process as the NSViews and NSWindows that they represent. Require an
-// explicit function call (GetNativeNSView or GetNativeNSWindow) to retrieve
-// the underlying NSView or NSWindow.
-// https://crbug.com/893719
+// process as the NSViews and NSWindows that they represent. Require an explicit
+// function call (GetNativeNSView or GetNativeNSWindow) to retrieve the
+// underlying NSView or NSWindow <https://crbug.com/893719>. These are wrapper
+// classes only and do not maintain any ownership, thus the __unsafe_unretained.
class GFX_EXPORT NativeView {
public:
- constexpr NativeView() {}
+ constexpr NativeView() = default;
// TODO(ccameron): Make this constructor explicit.
- constexpr NativeView(NSView* ns_view) : ns_view_(ns_view) {}
+ constexpr NativeView(__unsafe_unretained NSView* ns_view)
+ : ns_view_(ns_view) {}
// This function name is verbose (that is, not just GetNSView) so that it
// is easily grep-able.
NSView* GetNativeNSView() const { return ns_view_; }
- operator bool() const { return ns_view_ != 0; }
+ explicit operator bool() const { return ns_view_ != nullptr; }
bool operator==(const NativeView& other) const {
return ns_view_ == other.ns_view_;
}
@@ -157,21 +153,27 @@
bool operator<(const NativeView& other) const {
return ns_view_ < other.ns_view_;
}
+ std::string ToString() const;
private:
+#if defined(__has_feature) && __has_feature(objc_arc)
+ __unsafe_unretained NSView* ns_view_ = nullptr;
+#else
NSView* ns_view_ = nullptr;
+#endif
};
class GFX_EXPORT NativeWindow {
public:
- constexpr NativeWindow() {}
+ constexpr NativeWindow() = default;
// TODO(ccameron): Make this constructor explicit.
- constexpr NativeWindow(NSWindow* ns_window) : ns_window_(ns_window) {}
+ constexpr NativeWindow(__unsafe_unretained NSWindow* ns_window)
+ : ns_window_(ns_window) {}
// This function name is verbose (that is, not just GetNSWindow) so that it
// is easily grep-able.
NSWindow* GetNativeNSWindow() const { return ns_window_; }
- operator bool() const { return ns_window_ != 0; }
+ explicit operator bool() const { return ns_window_ != nullptr; }
bool operator==(const NativeWindow& other) const {
return ns_window_ == other.ns_window_;
}
@@ -181,42 +183,52 @@
bool operator<(const NativeWindow& other) const {
return ns_window_ < other.ns_window_;
}
+ std::string ToString() const;
private:
+#if defined(__has_feature) && __has_feature(objc_arc)
+ __unsafe_unretained NSWindow* ns_window_ = nullptr;
+#else
NSWindow* ns_window_ = nullptr;
+#endif
};
constexpr NativeView kNullNativeView = NativeView(nullptr);
constexpr NativeWindow kNullNativeWindow = NativeWindow(nullptr);
-#elif defined(OS_ANDROID)
-typedef void* NativeCursor;
-typedef ui::ViewAndroid* NativeView;
-typedef ui::WindowAndroid* NativeWindow;
-typedef base::android::ScopedJavaGlobalRef<jobject> NativeEvent;
+#elif BUILDFLAG(IS_ANDROID)
+using NativeCursor = void*;
+using NativeView = ui::ViewAndroid*;
+using NativeWindow = ui::WindowAndroid*;
+using NativeEvent = base::android::ScopedJavaGlobalRef<jobject>;
constexpr NativeView kNullNativeView = nullptr;
constexpr NativeWindow kNullNativeWindow = nullptr;
#else
#error Unknown build environment.
#endif
-#if defined(OS_WIN)
-typedef HFONT NativeFont;
-typedef IAccessible* NativeViewAccessible;
-#elif defined(OS_IOS)
-typedef UIFont* NativeFont;
-typedef id NativeViewAccessible;
-#elif defined(OS_MAC)
-typedef NSFont* NativeFont;
-typedef id NativeViewAccessible;
+#if BUILDFLAG(IS_WIN)
+using NativeViewAccessible = IAccessible*;
+#elif BUILDFLAG(IS_IOS)
+#ifdef __OBJC__
+using NativeViewAccessible = id;
+#else
+using NativeViewAccessible = struct objc_object*;
+#endif
+#elif BUILDFLAG(IS_MAC)
+#ifdef __OBJC__
+using NativeViewAccessible = id;
+#else
+using NativeViewAccessible = struct objc_object*;
+#endif
// TODO(crbug.com/1052397): Revisit the macro expression once build flag switch
// of lacros-chrome is complete.
-#elif defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS)
// Linux doesn't have a native font type.
-typedef AtkObject* NativeViewAccessible;
+using NativeViewAccessible = AtkObject*;
#else
// Android, Chrome OS, etc.
-typedef struct _UnimplementedNativeViewAccessible
- UnimplementedNativeViewAccessible;
-typedef UnimplementedNativeViewAccessible* NativeViewAccessible;
+using UnimplementedNativeViewAccessible =
+ struct _UnimplementedNativeViewAccessible;
+using NativeViewAccessible = UnimplementedNativeViewAccessible*;
#endif
// A constant value to indicate that gfx::NativeCursor refers to no cursor.
@@ -232,23 +244,23 @@
// test_shell.
//
// See comment at the top of the file for usage.
-typedef intptr_t NativeViewId;
+using NativeViewId = intptr_t;
// AcceleratedWidget provides a surface to compositors to paint pixels.
-#if defined(OS_WIN)
-typedef HWND AcceleratedWidget;
+#if BUILDFLAG(IS_WIN)
+using AcceleratedWidget = HWND;
constexpr AcceleratedWidget kNullAcceleratedWidget = nullptr;
-#elif defined(OS_IOS)
-typedef UIView* AcceleratedWidget;
+#elif BUILDFLAG(IS_IOS)
+using AcceleratedWidget = UIView*;
constexpr AcceleratedWidget kNullAcceleratedWidget = 0;
-#elif defined(OS_MAC)
-typedef uint64_t AcceleratedWidget;
+#elif BUILDFLAG(IS_MAC)
+using AcceleratedWidget = uint64_t;
constexpr AcceleratedWidget kNullAcceleratedWidget = 0;
-#elif defined(OS_ANDROID)
-typedef ANativeWindow* AcceleratedWidget;
+#elif BUILDFLAG(IS_ANDROID)
+using AcceleratedWidget = ANativeWindow*;
constexpr AcceleratedWidget kNullAcceleratedWidget = 0;
-#elif defined(USE_OZONE) || defined(USE_X11)
-typedef uint32_t AcceleratedWidget;
+#elif BUILDFLAG(IS_OZONE)
+using AcceleratedWidget = uint32_t;
constexpr AcceleratedWidget kNullAcceleratedWidget = 0;
#else
#error unknown platform
diff --git a/ui/gfx/native_widget_types.mm b/ui/gfx/native_widget_types.mm
new file mode 100644
index 0000000..b315ad6
--- /dev/null
+++ b/ui/gfx/native_widget_types.mm
@@ -0,0 +1,21 @@
+// Copyright 2023 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/native_widget_types.h"
+
+#include <AppKit/AppKit.h>
+
+#include "base/strings/sys_string_conversions.h"
+
+namespace gfx {
+
+std::string NativeView::ToString() const {
+ return base::SysNSStringToUTF8(ns_view_.description);
+}
+
+std::string NativeWindow::ToString() const {
+ return base::SysNSStringToUTF8(ns_window_.description);
+}
+
+} // namespace gfx
diff --git a/ui/gfx/nine_image_painter.cc b/ui/gfx/nine_image_painter.cc
index b2292b3..330bff9 100644
--- a/ui/gfx/nine_image_painter.cc
+++ b/ui/gfx/nine_image_painter.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,7 +8,6 @@
#include <limits>
-#include "base/cxx17_backports.h"
#include "base/numerics/safe_conversions.h"
#include "cc/paint/paint_flags.h"
#include "third_party/skia/include/core/SkRect.h"
@@ -19,6 +18,7 @@
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/image/image_skia_operations.h"
+#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/scoped_canvas.h"
namespace gfx {
@@ -52,8 +52,8 @@
} // namespace
NineImagePainter::NineImagePainter(const std::vector<ImageSkia>& images) {
- DCHECK_EQ(base::size(images_), images.size());
- for (size_t i = 0; i < base::size(images_); ++i)
+ DCHECK_EQ(std::size(images_), images.size());
+ for (size_t i = 0; i < std::size(images_); ++i)
images_[i] = images[i];
}
@@ -112,8 +112,8 @@
canvas->Translate(gfx::Vector2d(left_in_pixels, top_in_pixels));
ImageSkiaRep image_reps[9];
- static_assert(base::size(image_reps) == std::extent<decltype(images_)>(), "");
- for (size_t i = 0; i < base::size(image_reps); ++i) {
+ static_assert(std::size(image_reps) == std::extent<decltype(images_)>(), "");
+ for (size_t i = 0; i < std::size(image_reps); ++i) {
image_reps[i] = images_[i].GetRepresentation(scale);
DCHECK(image_reps[i].is_null() || image_reps[i].scale() == scale);
}
@@ -156,7 +156,7 @@
int i4h = std::max(height_in_pixels - i4y - std::min({i6h, i7h, i8h}), 0);
cc::PaintFlags flags;
- flags.setAlpha(alpha);
+ flags.setAlphaf(alpha / 255.0f);
Fill(canvas, image_reps[4], i4x, i4y, i4w, i4h, flags);
Fill(canvas, image_reps[0], 0, 0, i0w, i0h, flags);
diff --git a/ui/gfx/nine_image_painter.h b/ui/gfx/nine_image_painter.h
index caa6e3a..7274ef6 100644
--- a/ui/gfx/nine_image_painter.h
+++ b/ui/gfx/nine_image_painter.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,7 +10,6 @@
#include <vector>
#include "base/gtest_prod_util.h"
-#include "base/macros.h"
#include "ui/gfx/gfx_export.h"
#include "ui/gfx/image/image_skia.h"
diff --git a/ui/gfx/nine_image_painter_unittest.cc b/ui/gfx/nine_image_painter_unittest.cc
index 9897d00..0e13d7c 100644
--- a/ui/gfx/nine_image_painter_unittest.cc
+++ b/ui/gfx/nine_image_painter_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -13,6 +13,7 @@
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_rep.h"
namespace gfx {
@@ -49,7 +50,7 @@
SkBitmap src;
src.allocN32Pixels(40, 50);
const ImageSkia image_skia(ImageSkiaRep(src, 1.0));
- const Insets insets(1, 2, 3, 4);
+ const auto insets = gfx::Insets::TLBR(1, 2, 3, 4);
std::vector<Rect> rects;
NineImagePainter::GetSubsetRegions(image_skia, insets, &rects);
ASSERT_EQ(9u, rects.size());
@@ -73,7 +74,7 @@
float image_scale = 2.f;
gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(src, image_scale);
- gfx::Insets insets(10, 10, 10, 10);
+ gfx::Insets insets(10);
gfx::NineImagePainter painter(image, insets);
bool is_opaque = true;
@@ -105,7 +106,7 @@
src.erase(SK_ColorRED, SkIRect::MakeXYWH(2, 2, 2, 2));
gfx::ImageSkia image = gfx::ImageSkia::CreateFrom1xBitmap(src);
- gfx::Insets insets(2, 2, 2, 2);
+ gfx::Insets insets(2);
gfx::NineImagePainter painter(image, insets);
int image_scale = 1;
@@ -137,7 +138,7 @@
src.eraseArea(SkIRect::MakeXYWH(1, 1, 8, 8), SK_ColorGREEN);
gfx::ImageSkia image = gfx::ImageSkia::CreateFrom1xBitmap(src);
- gfx::Insets insets(1, 1, 1, 1);
+ gfx::Insets insets(1);
gfx::NineImagePainter painter(image, insets);
bool is_opaque = true;
@@ -169,7 +170,7 @@
float image_scale = 2.f;
gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(src, image_scale);
- gfx::Insets insets(10, 10, 10, 10);
+ gfx::Insets insets(10);
gfx::NineImagePainter painter(image, insets);
bool is_opaque = true;
@@ -200,7 +201,7 @@
float image_scale = 2.f;
gfx::ImageSkia image = gfx::ImageSkia::CreateFromBitmap(src, image_scale);
- gfx::Insets insets(10, 10, 10, 10);
+ gfx::Insets insets(10);
gfx::NineImagePainter painter(image, insets);
bool is_opaque = true;
diff --git a/ui/gfx/overlay_plane_data.cc b/ui/gfx/overlay_plane_data.cc
index 69c49bd..e63a6bc 100644
--- a/ui/gfx/overlay_plane_data.cc
+++ b/ui/gfx/overlay_plane_data.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,14 +8,21 @@
OverlayPlaneData::OverlayPlaneData() = default;
-OverlayPlaneData::OverlayPlaneData(int z_order,
- OverlayTransform plane_transform,
- const Rect& display_bounds,
- const RectF& crop_rect,
- bool enable_blend,
- const Rect& damage_rect,
- float opacity,
- OverlayPriorityHint priority_hint)
+OverlayPlaneData::OverlayPlaneData(
+ int z_order,
+ OverlayTransform plane_transform,
+ const RectF& display_bounds,
+ const RectF& crop_rect,
+ bool enable_blend,
+ const Rect& damage_rect,
+ float opacity,
+ OverlayPriorityHint priority_hint,
+ const gfx::RRectF& rounded_corners,
+ const gfx::ColorSpace& color_space,
+ const absl::optional<HDRMetadata>& hdr_metadata,
+ absl::optional<SkColor4f> color,
+ bool is_solid_color,
+ absl::optional<Rect> clip_rect)
: z_order(z_order),
plane_transform(plane_transform),
display_bounds(display_bounds),
@@ -23,8 +30,16 @@
enable_blend(enable_blend),
damage_rect(damage_rect),
opacity(opacity),
- priority_hint(priority_hint) {}
+ priority_hint(priority_hint),
+ rounded_corners(rounded_corners),
+ color_space(color_space),
+ hdr_metadata(hdr_metadata),
+ color(color),
+ is_solid_color(is_solid_color),
+ clip_rect(clip_rect) {}
OverlayPlaneData::~OverlayPlaneData() = default;
+OverlayPlaneData::OverlayPlaneData(const OverlayPlaneData& other) = default;
+
} // namespace gfx
diff --git a/ui/gfx/overlay_plane_data.h b/ui/gfx/overlay_plane_data.h
index 272ee21..002a9ae 100644
--- a/ui/gfx/overlay_plane_data.h
+++ b/ui/gfx/overlay_plane_data.h
@@ -1,13 +1,18 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_OVERLAY_PLANE_DATA_H_
#define UI_GFX_OVERLAY_PLANE_DATA_H_
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/color_space.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/rrect_f.h"
#include "ui/gfx/gfx_export.h"
+#include "ui/gfx/hdr_metadata.h"
#include "ui/gfx/overlay_priority_hint.h"
#include "ui/gfx/overlay_transform.h"
@@ -17,14 +22,22 @@
OverlayPlaneData();
OverlayPlaneData(int z_order,
OverlayTransform plane_transform,
- const Rect& display_bounds,
+ const RectF& display_bounds,
const RectF& crop_rect,
bool enable_blend,
const Rect& damage_rect,
float opacity,
- OverlayPriorityHint priority_hint);
+ OverlayPriorityHint priority_hint,
+ const gfx::RRectF& rounded_corners,
+ const gfx::ColorSpace& color_space,
+ const absl::optional<HDRMetadata>& hdr_metadata,
+ absl::optional<SkColor4f> color = absl::nullopt,
+ bool is_solid_color = false,
+ absl::optional<Rect> clip_rect = absl::nullopt);
~OverlayPlaneData();
+ OverlayPlaneData(const OverlayPlaneData& other);
+
// Specifies the stacking order of the plane relative to the main framebuffer
// located at index 0.
int z_order = 0;
@@ -32,8 +45,10 @@
// Specifies how the buffer is to be transformed during composition.
OverlayTransform plane_transform = OverlayTransform::OVERLAY_TRANSFORM_NONE;
- // Pixel bounds within the display to position the image.
- Rect display_bounds;
+ // Bounds within the display to position the image in pixel coordinates. They
+ // are sent as floating point rect as some backends such as Wayland are able
+ // to do delegated compositing with sub-pixel accurate positioning.
+ RectF display_bounds;
// Normalized bounds of the image to be displayed in |display_bounds|.
RectF crop_rect = RectF(1.f, 1.f);
@@ -50,6 +65,25 @@
// Hints for overlay prioritization when delegated composition is used.
OverlayPriorityHint priority_hint = OverlayPriorityHint::kNone;
+
+ // Specifies the rounded corners of overlay plane.
+ RRectF rounded_corners;
+
+ // ColorSpace for this overlay.
+ gfx::ColorSpace color_space;
+
+ // Optional HDR meta data required to display this overlay.
+ absl::optional<HDRMetadata> hdr_metadata;
+
+ // Represents either a background of this overlay or a color of a solid color
+ // quad, which can be checked via the |is_solid_color|.
+ absl::optional<SkColor4f> color;
+
+ // Set if this is a solid color quad.
+ bool is_solid_color;
+
+ // Optional clip rect for this overlay.
+ absl::optional<gfx::Rect> clip_rect;
};
} // namespace gfx
diff --git a/ui/gfx/overlay_priority_hint.h b/ui/gfx/overlay_priority_hint.h
index 1ae4d6e..9913cc0 100644
--- a/ui/gfx/overlay_priority_hint.h
+++ b/ui/gfx/overlay_priority_hint.h
@@ -1,15 +1,17 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_OVERLAY_PRIORITY_HINT_H_
#define UI_GFX_OVERLAY_PRIORITY_HINT_H_
+#include <stdint.h>
+
namespace gfx {
// Provides a hint to a system compositor how it should prioritize this
// overlay. Used only by Wayland.
-enum OverlayPriorityHint {
+enum OverlayPriorityHint : uint8_t {
// Overlay promotion is not necessary for this surface.
kNone = 0,
// The overlay could be considered as a candidate for promotion.
@@ -19,6 +21,8 @@
// The overlay contains protected content and requires to be promoted to
// overlay.
kHardwareProtection,
+ // The overlay contains a video. Can be a candidate for promotion.
+ kVideo,
};
} // namespace gfx
diff --git a/ui/gfx/overlay_transform.h b/ui/gfx/overlay_transform.h
index 252fc73..0aa806d 100644
--- a/ui/gfx/overlay_transform.h
+++ b/ui/gfx/overlay_transform.h
@@ -1,15 +1,18 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_OVERLAY_TRANSFORM_H_
#define UI_GFX_OVERLAY_TRANSFORM_H_
+#include <stdint.h>
+
namespace gfx {
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.ui.gfx
// Describes transformation to be applied to the buffer before presenting
// to screen. Rotations are expressed anticlockwise.
-enum OverlayTransform {
+enum OverlayTransform : uint8_t {
OVERLAY_TRANSFORM_INVALID,
OVERLAY_TRANSFORM_NONE,
OVERLAY_TRANSFORM_FLIP_HORIZONTAL,
diff --git a/ui/gfx/overlay_transform_utils.cc b/ui/gfx/overlay_transform_utils.cc
index c39345e..5d23bb5 100644
--- a/ui/gfx/overlay_transform_utils.cc
+++ b/ui/gfx/overlay_transform_utils.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,57 +9,51 @@
namespace gfx {
-gfx::Transform OverlayTransformToTransform(
- gfx::OverlayTransform overlay_transform,
- const gfx::SizeF& viewport_bounds) {
+Transform OverlayTransformToTransform(OverlayTransform overlay_transform,
+ const SizeF& viewport_bounds) {
switch (overlay_transform) {
- case gfx::OVERLAY_TRANSFORM_INVALID:
+ case OVERLAY_TRANSFORM_INVALID:
NOTREACHED();
- return gfx::Transform();
- case gfx::OVERLAY_TRANSFORM_NONE:
- return gfx::Transform();
- case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
- return gfx::Transform(
- SkMatrix::MakeAll(-1, 0, viewport_bounds.width(), 0, 1, 0, 0, 0, 1));
- case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
- return gfx::Transform(
- SkMatrix::MakeAll(1, 0, 0, 0, -1, viewport_bounds.height(), 0, 0, 1));
- case gfx::OVERLAY_TRANSFORM_ROTATE_90:
- return gfx::Transform(
- SkMatrix::MakeAll(0, -1, viewport_bounds.height(), 1, 0, 0, 0, 0, 1));
- case gfx::OVERLAY_TRANSFORM_ROTATE_180:
- return gfx::Transform(SkMatrix::MakeAll(-1, 0, viewport_bounds.width(), 0,
- -1, viewport_bounds.height(), 0,
- 0, 1));
- case gfx::OVERLAY_TRANSFORM_ROTATE_270:
- return gfx::Transform(
- SkMatrix::MakeAll(0, 1, 0, -1, 0, viewport_bounds.width(), 0, 0, 1));
+ return Transform();
+ case OVERLAY_TRANSFORM_NONE:
+ return Transform();
+ case OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+ return Transform::Affine(-1, 0, 0, 1, viewport_bounds.width(), 0);
+ case OVERLAY_TRANSFORM_FLIP_VERTICAL:
+ return Transform::Affine(1, 0, 0, -1, 0, viewport_bounds.height());
+ case OVERLAY_TRANSFORM_ROTATE_90:
+ return Transform::Affine(0, 1, -1, 0, viewport_bounds.height(), 0);
+ case OVERLAY_TRANSFORM_ROTATE_180:
+ return Transform::Affine(-1, 0, 0, -1, viewport_bounds.width(),
+ viewport_bounds.height());
+ case OVERLAY_TRANSFORM_ROTATE_270:
+ return Transform::Affine(0, -1, 1, 0, 0, viewport_bounds.width());
}
NOTREACHED();
- return gfx::Transform();
+ return Transform();
}
-gfx::OverlayTransform InvertOverlayTransform(gfx::OverlayTransform transform) {
+OverlayTransform InvertOverlayTransform(OverlayTransform transform) {
switch (transform) {
- case gfx::OVERLAY_TRANSFORM_INVALID:
+ case OVERLAY_TRANSFORM_INVALID:
NOTREACHED();
- return gfx::OVERLAY_TRANSFORM_NONE;
- case gfx::OVERLAY_TRANSFORM_NONE:
- return gfx::OVERLAY_TRANSFORM_NONE;
- case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
- return gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL;
- case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
- return gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL;
- case gfx::OVERLAY_TRANSFORM_ROTATE_90:
- return gfx::OVERLAY_TRANSFORM_ROTATE_270;
- case gfx::OVERLAY_TRANSFORM_ROTATE_180:
- return gfx::OVERLAY_TRANSFORM_ROTATE_180;
- case gfx::OVERLAY_TRANSFORM_ROTATE_270:
- return gfx::OVERLAY_TRANSFORM_ROTATE_90;
+ return OVERLAY_TRANSFORM_NONE;
+ case OVERLAY_TRANSFORM_NONE:
+ return OVERLAY_TRANSFORM_NONE;
+ case OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
+ return OVERLAY_TRANSFORM_FLIP_HORIZONTAL;
+ case OVERLAY_TRANSFORM_FLIP_VERTICAL:
+ return OVERLAY_TRANSFORM_FLIP_VERTICAL;
+ case OVERLAY_TRANSFORM_ROTATE_90:
+ return OVERLAY_TRANSFORM_ROTATE_270;
+ case OVERLAY_TRANSFORM_ROTATE_180:
+ return OVERLAY_TRANSFORM_ROTATE_180;
+ case OVERLAY_TRANSFORM_ROTATE_270:
+ return OVERLAY_TRANSFORM_ROTATE_90;
}
NOTREACHED();
- return gfx::OVERLAY_TRANSFORM_NONE;
+ return OVERLAY_TRANSFORM_NONE;
}
} // namespace gfx
diff --git a/ui/gfx/overlay_transform_utils.h b/ui/gfx/overlay_transform_utils.h
index 5df8e43..50a7f33 100644
--- a/ui/gfx/overlay_transform_utils.h
+++ b/ui/gfx/overlay_transform_utils.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -12,12 +12,11 @@
namespace gfx {
-GFX_EXPORT gfx::Transform OverlayTransformToTransform(
- gfx::OverlayTransform overlay_transform,
- const gfx::SizeF& viewport_bounds);
+GFX_EXPORT Transform
+OverlayTransformToTransform(OverlayTransform overlay_transform,
+ const SizeF& viewport_bounds);
-GFX_EXPORT gfx::OverlayTransform InvertOverlayTransform(
- gfx::OverlayTransform transform);
+GFX_EXPORT OverlayTransform InvertOverlayTransform(OverlayTransform transform);
} // namespace gfx
diff --git a/ui/gfx/overlay_transform_utils_unittest.cc b/ui/gfx/overlay_transform_utils_unittest.cc
index 8090a0e..d4bea64 100644
--- a/ui/gfx/overlay_transform_utils_unittest.cc
+++ b/ui/gfx/overlay_transform_utils_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/paint_throbber.cc b/ui/gfx/paint_throbber.cc
index bea7d99..a59f8f6 100644
--- a/ui/gfx/paint_throbber.cc
+++ b/ui/gfx/paint_throbber.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -48,7 +48,7 @@
// Inset by half the stroke width to make sure the whole arc is inside
// the visible rect.
const int inset = SkScalarCeilToInt(*stroke_width / 2.0);
- oval.Inset(inset, inset);
+ oval.Inset(inset);
SkPath path;
path.arcTo(RectToSkRect(oval), start_angle, sweep, true);
diff --git a/ui/gfx/paint_throbber.h b/ui/gfx/paint_throbber.h
index c22d0f9..9d02845 100644
--- a/ui/gfx/paint_throbber.h
+++ b/ui/gfx/paint_throbber.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/paint_vector_icon.cc b/ui/gfx/paint_vector_icon.cc
index b998717..60de4ab 100644
--- a/ui/gfx/paint_vector_icon.cc
+++ b/ui/gfx/paint_vector_icon.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,7 +10,7 @@
#include "base/i18n/rtl.h"
#include "base/lazy_instance.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
@@ -73,10 +73,10 @@
struct CompareIconDescription {
bool operator()(const IconDescription& a, const IconDescription& b) const {
- const VectorIcon* a_icon = &a.icon;
- const VectorIcon* b_icon = &b.icon;
- const VectorIcon* a_badge = &a.badge_icon;
- const VectorIcon* b_badge = &b.badge_icon;
+ const VectorIcon* a_icon = &*a.icon;
+ const VectorIcon* b_icon = &*b.icon;
+ const VectorIcon* a_badge = &*a.badge_icon;
+ const VectorIcon* b_badge = &*b.badge_icon;
return std::tie(a_icon, a.dip_size, a.color, a_badge) <
std::tie(b_icon, b.dip_size, b.color, b_badge);
}
@@ -161,7 +161,7 @@
return 0;
}
- const PathElement* path_elements_;
+ raw_ptr<const PathElement> path_elements_;
size_t path_size_;
size_t command_index_ = 0;
};
@@ -273,7 +273,7 @@
break;
case PATH_COLOR_ALPHA:
- flags.setAlpha(SkScalarFloorToInt(arg(0)));
+ flags.setAlphaf(SkScalarFloorToInt(arg(0)) / 255.0f);
break;
case PATH_COLOR_ARGB:
@@ -489,14 +489,14 @@
// CanvasImageSource:
bool HasRepresentationAtAllScales() const override {
- return !data_.icon.is_empty();
+ return !data_.icon->is_empty();
}
void Draw(Canvas* canvas) override {
if (path_.empty()) {
- PaintVectorIcon(canvas, data_.icon, size_.width(), data_.color);
- if (!data_.badge_icon.is_empty())
- PaintVectorIcon(canvas, data_.badge_icon, size_.width(), data_.color);
+ PaintVectorIcon(canvas, *data_.icon, size_.width(), data_.color);
+ if (!data_.badge_icon->is_empty())
+ PaintVectorIcon(canvas, *data_.badge_icon, size_.width(), data_.color);
} else {
PaintPath(canvas, path_.data(), path_.size(), size_.width(), data_.color);
}
@@ -574,7 +574,7 @@
}
ImageSkia CreateVectorIcon(const IconDescription& params) {
- if (params.icon.is_empty())
+ if (params.icon->is_empty())
return ImageSkia();
return g_icon_cache.Get().GetOrCreateIcon(params);
diff --git a/ui/gfx/paint_vector_icon.h b/ui/gfx/paint_vector_icon.h
index c005bfa..09f7389 100644
--- a/ui/gfx/paint_vector_icon.h
+++ b/ui/gfx/paint_vector_icon.h
@@ -1,10 +1,11 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_PAINT_VECTOR_ICON_H_
#define UI_GFX_PAINT_VECTOR_ICON_H_
+#include "base/memory/raw_ref.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/color_palette.h"
#include "ui/gfx/gfx_export.h"
@@ -29,10 +30,10 @@
~IconDescription();
- const VectorIcon& icon;
+ const raw_ref<const VectorIcon> icon;
int dip_size;
SkColor color;
- const VectorIcon& badge_icon;
+ const raw_ref<const VectorIcon> badge_icon;
};
GFX_EXPORT extern const VectorIcon kNoneIcon;
diff --git a/ui/gfx/paint_vector_icon_unittest.cc b/ui/gfx/paint_vector_icon_unittest.cc
index ff7bd2e..e9c96fd 100644
--- a/ui/gfx/paint_vector_icon_unittest.cc
+++ b/ui/gfx/paint_vector_icon_unittest.cc
@@ -1,13 +1,13 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/paint_vector_icon.h"
#include <gtest/gtest.h>
+
#include <vector>
-#include "base/cxx17_backports.h"
#include "base/i18n/rtl.h"
#include "cc/paint/paint_record.h"
#include "cc/paint/paint_recorder.h"
@@ -46,20 +46,20 @@
// (CLOSE) uses the correct starting point. See crbug.com/697497
TEST(VectorIconTest, RelativeMoveToAfterClose) {
cc::PaintRecorder recorder;
- Canvas canvas(recorder.beginRecording(100, 100), 1.0f);
+ Canvas canvas(recorder.beginRecording(), 1.0f);
const PathElement elements[] = {
MOVE_TO, 4, 5, LINE_TO, 10, 11, CLOSE,
// This move should use (4, 5) as the start point rather than (10, 11).
R_MOVE_TO, 20, 21, R_LINE_TO, 50, 51};
- const VectorIconRep rep_list[] = {{elements, base::size(elements)}};
- const VectorIcon icon = {rep_list, 1u};
+ const VectorIconRep rep_list[] = {{elements, std::size(elements)}};
+ const VectorIcon icon(rep_list, 1u, nullptr);
PaintVectorIcon(&canvas, icon, 100, SK_ColorMAGENTA);
- sk_sp<cc::PaintRecord> record = recorder.finishRecordingAsPicture();
+ cc::PaintRecord record = recorder.finishRecordingAsPicture();
MockCanvas mock(100, 100);
- record->Playback(&mock);
+ record.Playback(&mock);
ASSERT_EQ(1U, mock.paths().size());
SkPoint last_point;
@@ -93,8 +93,8 @@
R_H_LINE_TO,
-20,
CLOSE};
- const VectorIconRep rep_list[] = {{elements, base::size(elements)}};
- const VectorIcon icon = {rep_list, 1u};
+ const VectorIconRep rep_list[] = {{elements, std::size(elements)}};
+ const VectorIcon icon(rep_list, 1u, nullptr);
PaintVectorIcon(&canvas, icon, canvas_size, color);
// Count the number of pixels in the canvas.
@@ -219,12 +219,12 @@
0,
CLOSE};
// VectorIconReps are always sorted in descending order of size.
- const VectorIconRep rep_list[] = {{elements48, base::size(elements48)},
- {elements32, base::size(elements32)},
- {elements24, base::size(elements24)},
- {elements20, base::size(elements20)},
- {elements16, base::size(elements16)}};
- const VectorIcon icon = {rep_list, 5u};
+ const VectorIconRep rep_list[] = {{elements48, std::size(elements48)},
+ {elements32, std::size(elements32)},
+ {elements24, std::size(elements24)},
+ {elements20, std::size(elements20)},
+ {elements16, std::size(elements16)}};
+ const VectorIcon icon(rep_list, 5u, nullptr);
// Test exact sizes paint the correctly sized icon, including the largest and
// smallest icon.
diff --git a/ui/gfx/path_mac.h b/ui/gfx/path_mac.h
deleted file mode 100644
index f20fa62..0000000
--- a/ui/gfx/path_mac.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_PATH_MAC_H_
-#define UI_GFX_PATH_MAC_H_
-
-#include "ui/gfx/gfx_export.h"
-
-@class NSBezierPath;
-class SkPath;
-
-namespace gfx {
-
-// Returns an autoreleased NSBezierPath corresponding to |path|. Caller should
-// call retain on the returned object, if it wishes to take ownership.
-GFX_EXPORT NSBezierPath* CreateNSBezierPathFromSkPath(const SkPath& path);
-
-} // namespace gfx
-
-#endif // UI_GFX_PATH_MAC_H_
diff --git a/ui/gfx/path_mac.mm b/ui/gfx/path_mac.mm
deleted file mode 100644
index fd82ad9..0000000
--- a/ui/gfx/path_mac.mm
+++ /dev/null
@@ -1,129 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/gfx/path_mac.h"
-
-#include <ostream>
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/cxx17_backports.h"
-#include "base/notreached.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "third_party/skia/include/core/SkRegion.h"
-
-namespace {
-
-// Convert a quadratic bezier curve to a cubic bezier curve. Based on the
-// implementation of the private SkConvertQuadToCubic method inside Skia.
-void ConvertQuadToCubicBezier(NSPoint quad[3], NSPoint cubic[4]) {
- // The resultant cubic will have the same endpoints.
- cubic[0] = quad[0];
- cubic[3] = quad[2];
-
- const double scale = 2.0 / 3.0;
-
- cubic[1].x = quad[0].x + scale * (quad[1].x - quad[0].x);
- cubic[1].y = quad[0].y + scale * (quad[1].y - quad[0].y);
-
- cubic[2].x = quad[2].x + scale * (quad[1].x - quad[2].x);
- cubic[2].y = quad[2].y + scale * (quad[1].y - quad[2].y);
-}
-
-} // namespace
-
-namespace gfx {
-
-NSBezierPath* CreateNSBezierPathFromSkPath(const SkPath& path) {
- NSBezierPath* result = [NSBezierPath bezierPath];
- SkPath::RawIter iter(path);
- SkPoint sk_points[4] = {{0.0}};
- SkPath::Verb verb;
- NSPoint points[4];
- while ((verb = iter.next(sk_points)) != SkPath::kDone_Verb) {
- for (size_t i = 0; i < base::size(points); i++)
- points[i] = NSMakePoint(sk_points[i].x(), sk_points[i].y());
-
- switch (verb) {
- case SkPath::kMove_Verb: {
- [result moveToPoint:points[0]];
- break;
- }
- case SkPath::kLine_Verb: {
- DCHECK(NSEqualPoints([result currentPoint], points[0]));
- [result lineToPoint:points[1]];
- break;
- }
- case SkPath::kQuad_Verb: {
- DCHECK(NSEqualPoints([result currentPoint], points[0]));
- NSPoint quad[] = {points[0], points[1], points[2]};
- // NSBezierPath does not support quadratic bezier curves. Hence convert
- // to cubic bezier curve.
- ConvertQuadToCubicBezier(quad, points);
- [result curveToPoint:points[3]
- controlPoint1:points[1]
- controlPoint2:points[2]];
- break;
- }
- case SkPath::kConic_Verb: {
- DCHECK(NSEqualPoints([result currentPoint], points[0]));
- // Approximate with quads. Use two for now, increase if more precision
- // is needed.
- const size_t kSubdivisionLevels = 1;
- const size_t kQuadCount = 1 << kSubdivisionLevels;
- // The quads will share endpoints, so we need one more point than twice
- // the number of quads.
- const size_t kPointCount = 1 + 2 * kQuadCount;
- SkPoint quads[kPointCount];
- SkPath::ConvertConicToQuads(sk_points[0], sk_points[1], sk_points[2],
- iter.conicWeight(), quads,
- kSubdivisionLevels);
- NSPoint ns_quads[kPointCount];
- for (size_t i = 0; i < kPointCount; i++)
- ns_quads[i] = NSMakePoint(quads[i].x(), quads[i].y());
-
- for (size_t i = 0; i < kQuadCount; i++) {
- NSPoint quad[] = {ns_quads[2 * i], ns_quads[2 * i + 1],
- ns_quads[2 * i + 2]};
- ConvertQuadToCubicBezier(quad, points);
- DCHECK(NSEqualPoints([result currentPoint], points[0]));
- [result curveToPoint:points[3]
- controlPoint1:points[1]
- controlPoint2:points[2]];
- }
- break;
- }
- case SkPath::kCubic_Verb: {
- DCHECK(NSEqualPoints([result currentPoint], points[0]));
- [result curveToPoint:points[3]
- controlPoint1:points[1]
- controlPoint2:points[2]];
- break;
- }
- case SkPath::kClose_Verb: {
- [result closePath];
- break;
- }
- default: { NOTREACHED(); }
- }
- }
-
- // Set up the fill type.
- switch (path.getFillType()) {
- case SkPathFillType::kWinding:
- [result setWindingRule:NSNonZeroWindingRule];
- break;
- case SkPathFillType::kEvenOdd:
- [result setWindingRule:NSEvenOddWindingRule];
- break;
- case SkPathFillType::kInverseWinding:
- case SkPathFillType::kInverseEvenOdd:
- NOTREACHED() << "NSBezierCurve does not support inverse fill types.";
- break;
- }
-
- return result;
-}
-
-} // namespace gfx
diff --git a/ui/gfx/path_mac_unittest.mm b/ui/gfx/path_mac_unittest.mm
deleted file mode 100644
index 149c4e3..0000000
--- a/ui/gfx/path_mac_unittest.mm
+++ /dev/null
@@ -1,260 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ui/gfx/path_mac.h"
-
-#include <cmath>
-#include <vector>
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/check_op.h"
-#include "base/cxx17_backports.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkPath.h"
-#include "third_party/skia/include/core/SkRegion.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-
-namespace gfx {
-
-namespace {
-
-// Returns the point at a distance of |radius| from the point (|centre_x|,
-// |centre_y|), and angle |degrees| from the positive horizontal axis, measured
-// anti-clockwise.
-NSPoint GetRadialPoint(double radius,
- double degrees,
- double centre_x,
- double centre_y) {
- const double radian = (degrees * SK_ScalarPI) / 180;
- return NSMakePoint(centre_x + radius * std::cos(radian),
- centre_y + radius * std::sin(radian));
-}
-
-// Returns the area of a circle with the given |radius|.
-double CalculateCircleArea(double radius) {
- return SK_ScalarPI * radius * radius;
-}
-
-// Returns the area of a simple polygon. |path| should represent a simple
-// polygon.
-double CalculatePolygonArea(NSBezierPath* path) {
- // If path represents a single polygon, it will have MoveTo, followed by
- // multiple LineTo, followed By ClosePath, followed by another MoveTo
- // NSBezierPathElement.
- const size_t element_count = [path elementCount];
- NSPoint points[3];
- std::vector<NSPoint> poly;
-
- for (size_t i = 0; i < element_count - 1; i++) {
- NSBezierPathElement element =
- [path elementAtIndex:i associatedPoints:points];
- poly.push_back(points[0]);
- DCHECK_EQ(element,
- i ? (i == element_count - 2 ? NSClosePathBezierPathElement
- : NSLineToBezierPathElement)
- : NSMoveToBezierPathElement);
- }
- DCHECK_EQ([path elementAtIndex:element_count - 1], NSMoveToBezierPathElement);
-
- // Shoelace Algorithm to find the area of a simple polygon.
- DCHECK(NSEqualPoints(poly.front(), poly.back()));
- double area = 0;
- for (size_t i = 0; i < poly.size() - 1; i++)
- area += poly[i].x * poly[i + 1].y - poly[i].y * poly[i + 1].x;
-
- return std::fabs(area) / 2.0;
-}
-
-// Returns the area of a rounded rectangle with the given |width|, |height| and
-// |radius|.
-double CalculateRoundedRectangleArea(double width,
- double height,
- double radius) {
- const double inside_width = width - 2 * radius;
- const double inside_height = height - 2 * radius;
- return inside_width * inside_height +
- 2 * radius * (inside_width + inside_height) +
- CalculateCircleArea(radius);
-}
-
-// Returns the bounding box of |path| as a Rect.
-Rect GetBoundingBox(NSBezierPath* path) {
- const NSRect bounds = [path bounds];
- return ToNearestRect(RectF(bounds.origin.x, bounds.origin.y,
- bounds.size.width, bounds.size.height));
-}
-
-} // namespace
-
-// Check that empty NSBezierPath is returned for empty SkPath.
-TEST(CreateNSBezierPathFromSkPathTest, EmptyPath) {
- NSBezierPath* result = CreateNSBezierPathFromSkPath(SkPath());
- EXPECT_TRUE([result isEmpty]);
-}
-
-// Check that the returned NSBezierPath has the correct winding rule.
-TEST(CreateNSBezierPathFromSkPathTest, FillType) {
- SkPath path;
- path.setFillType(SkPathFillType::kWinding);
- NSBezierPath* result = CreateNSBezierPathFromSkPath(path);
- EXPECT_EQ(NSNonZeroWindingRule, [result windingRule]);
-
- path.setFillType(SkPathFillType::kEvenOdd);
- result = CreateNSBezierPathFromSkPath(path);
- EXPECT_EQ(NSEvenOddWindingRule, [result windingRule]);
-}
-
-// Check that a path containing multiple subpaths, in this case two rectangles,
-// is correctly converted to a NSBezierPath.
-TEST(CreateNSBezierPathFromSkPathTest, TwoRectanglesPath) {
- const SkRect rects[] = {
- {0, 0, 50, 50}, {100, 100, 150, 150},
- };
- const NSPoint inside_points[] = {
- {1, 1}, {1, 49}, {49, 49}, {49, 1}, {25, 25},
- {101, 101}, {101, 149}, {149, 149}, {149, 101}, {125, 125}};
- const NSPoint outside_points[] = {{-1, -1}, {-1, 51}, {51, 51}, {51, -1},
- {99, 99}, {99, 151}, {151, 151}, {151, 99},
- {75, 75}, {-5, -5}};
- ASSERT_EQ(base::size(inside_points), base::size(outside_points));
- const Rect expected_bounds(0, 0, 150, 150);
-
- SkPath path;
- path.addRect(rects[0]);
- path.addRect(rects[1]);
- NSBezierPath* result = CreateNSBezierPathFromSkPath(path);
-
- // Check points near the boundary of the path and verify that they are
- // reported correctly as being inside/outside the path.
- for (size_t i = 0; i < base::size(inside_points); i++) {
- EXPECT_TRUE([result containsPoint:inside_points[i]]);
- EXPECT_FALSE([result containsPoint:outside_points[i]]);
- }
-
- // Check that the returned result has the correct bounding box. GetBoundingBox
- // rounds the coordinates to nearest integer values.
- EXPECT_EQ(expected_bounds, GetBoundingBox(result));
-}
-
-// Test that an SKPath containing a circle is converted correctly to a
-// NSBezierPath.
-TEST(CreateNSBezierPathFromSkPathTest, CirclePath) {
- const int kRadius = 5;
- const int kCentreX = 10;
- const int kCentreY = 15;
- const double kCushion = 0.1;
- // Expected bounding box of the circle.
- const Rect expected_bounds(kCentreX - kRadius, kCentreY - kRadius,
- 2 * kRadius, 2 * kRadius);
-
- SkPath path;
- path.addCircle(SkIntToScalar(kCentreX), SkIntToScalar(kCentreY),
- SkIntToScalar(kRadius));
- NSBezierPath* result = CreateNSBezierPathFromSkPath(path);
-
- // Check points near the boundary of the circle and verify that they are
- // reported correctly as being inside/outside the path.
- for (size_t deg = 0; deg < 360; deg++) {
- NSPoint inside_point =
- GetRadialPoint(kRadius - kCushion, deg, kCentreX, kCentreY);
- NSPoint outside_point =
- GetRadialPoint(kRadius + kCushion, deg, kCentreX, kCentreY);
- EXPECT_TRUE([result containsPoint:inside_point]);
- EXPECT_FALSE([result containsPoint:outside_point]);
- }
-
- // Check that the returned result has the correct bounding box. GetBoundingBox
- // rounds the coordinates to nearest integer values.
- EXPECT_EQ(expected_bounds, GetBoundingBox(result));
-
- // Check area of converted path is correct up to a certain tolerance value. To
- // find the area of the NSBezierPath returned, flatten it i.e. convert it to a
- // polygon.
- [NSBezierPath setDefaultFlatness:0.01];
- NSBezierPath* polygon = [result bezierPathByFlatteningPath];
- const double kTolerance = 0.14;
- EXPECT_NEAR(CalculateCircleArea(kRadius), CalculatePolygonArea(polygon),
- kTolerance);
-}
-
-// Test that an SKPath containing a rounded rectangle is converted correctly to
-// a NSBezierPath.
-TEST(CreateNSBezierPathFromSkPathTest, RoundedRectanglePath) {
- const int kRectangleWidth = 50;
- const int kRectangleHeight = 100;
- const int kCornerRadius = 5;
- const double kCushion = 0.1;
- // Expected bounding box of the rounded rectangle.
- const Rect expected_bounds(kRectangleWidth, kRectangleHeight);
-
- SkRRect rrect;
- rrect.setRectXY(SkRect::MakeWH(kRectangleWidth, kRectangleHeight),
- kCornerRadius, kCornerRadius);
-
- const NSPoint inside_points[] = {
- // Bottom left corner.
- {kCornerRadius / 2.0, kCornerRadius / 2.0},
- // Bottom right corner.
- {kRectangleWidth - kCornerRadius / 2.0, kCornerRadius / 2.0},
- // Top Right corner.
- {kRectangleWidth - kCornerRadius / 2.0,
- kRectangleHeight - kCornerRadius / 2.0},
- // Top left corner.
- {kCornerRadius / 2.0, kRectangleHeight - kCornerRadius / 2.0},
- // Bottom middle.
- {kRectangleWidth / 2.0, kCushion},
- // Right middle.
- {kRectangleWidth - kCushion, kRectangleHeight / 2.0},
- // Top middle.
- {kRectangleWidth / 2.0, kRectangleHeight - kCushion},
- // Left middle.
- {kCushion, kRectangleHeight / 2.0}};
- const NSPoint outside_points[] = {
- // Bottom left corner.
- {0, 0},
- // Bottom right corner.
- {kRectangleWidth, 0},
- // Top right corner.
- {kRectangleWidth, kRectangleHeight},
- // Top left corner.
- {0, kRectangleHeight},
- // Bottom middle.
- {kRectangleWidth / 2.0, -kCushion},
- // Right middle.
- {kRectangleWidth + kCushion, kRectangleHeight / 2.0},
- // Top middle.
- {kRectangleWidth / 2.0, kRectangleHeight + kCushion},
- // Left middle.
- {-kCushion, kRectangleHeight / 2.0}};
- ASSERT_EQ(base::size(inside_points), base::size(outside_points));
-
- SkPath path;
- path.addRRect(rrect);
- NSBezierPath* result = CreateNSBezierPathFromSkPath(path);
-
- // Check points near the boundary of the path and verify that they are
- // reported correctly as being inside/outside the path.
- for (size_t i = 0; i < base::size(inside_points); i++) {
- EXPECT_TRUE([result containsPoint:inside_points[i]]);
- EXPECT_FALSE([result containsPoint:outside_points[i]]);
- }
-
- // Check that the returned result has the correct bounding box. GetBoundingBox
- // rounds the coordinates to nearest integer values.
- EXPECT_EQ(expected_bounds, GetBoundingBox(result));
-
- // Check area of converted path is correct up to a certain tolerance value. To
- // find the area of the NSBezierPath returned, flatten it i.e. convert it to a
- // polygon.
- [NSBezierPath setDefaultFlatness:0.01];
- NSBezierPath* polygon = [result bezierPathByFlatteningPath];
- const double kTolerance = 0.14;
- EXPECT_NEAR(CalculateRoundedRectangleArea(kRectangleWidth, kRectangleHeight,
- kCornerRadius),
- CalculatePolygonArea(polygon), kTolerance);
-}
-
-} // namespace gfx
diff --git a/ui/gfx/path_win.cc b/ui/gfx/path_win.cc
index 3a73d91..70037a8 100644
--- a/ui/gfx/path_win.cc
+++ b/ui/gfx/path_win.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/path_win.h b/ui/gfx/path_win.h
index 2b85075..5ece155 100644
--- a/ui/gfx/path_win.h
+++ b/ui/gfx/path_win.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/path_win_unittest.cc b/ui/gfx/path_win_unittest.cc
index c001370..59f3ac8 100644
--- a/ui/gfx/path_win_unittest.cc
+++ b/ui/gfx/path_win_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,11 +6,11 @@
#include <stddef.h>
-#include <algorithm>
#include <vector>
#include "base/check_op.h"
-#include "base/cxx17_backports.h"
+#include "base/containers/span.h"
+#include "base/ranges/algorithm.h"
#include "base/win/scoped_gdi_object.h"
#include "skia/ext/skia_utils_win.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -34,10 +34,10 @@
CHECK_EQ(bytes_size, result);
// Pull out the rectangles into a SkIRect vector to return to caller.
- const LPRECT rects = reinterpret_cast<LPRECT>(®ion_data->Buffer[0]);
- std::vector<SkIRect> sk_rects(region_data->rdh.nCount);
- std::transform(rects, rects + region_data->rdh.nCount,
- sk_rects.begin(), skia::RECTToSkIRect);
+ base::span<RECT> rects(reinterpret_cast<RECT*>(®ion_data->Buffer[0]),
+ region_data->rdh.nCount);
+ std::vector<SkIRect> sk_rects(rects.size());
+ base::ranges::transform(rects, sk_rects.begin(), skia::RECTToSkIRect);
return sk_rects;
}
@@ -84,8 +84,8 @@
path.addRRect(rrect);
base::win::ScopedRegion region(CreateHRGNFromSkPath(path));
const std::vector<SkIRect>& region_rects = GetRectsFromHRGN(region.get());
- EXPECT_EQ(base::size(rects), region_rects.size());
- for (size_t i = 0; i < base::size(rects) && i < region_rects.size(); ++i)
+ EXPECT_EQ(std::size(rects), region_rects.size());
+ for (size_t i = 0; i < std::size(rects) && i < region_rects.size(); ++i)
EXPECT_EQ(rects[i], region_rects[i]);
}
@@ -103,8 +103,8 @@
}
base::win::ScopedRegion region(CreateHRGNFromSkPath(path));
const std::vector<SkIRect>& region_rects = GetRectsFromHRGN(region.get());
- ASSERT_EQ(base::size(rects), region_rects.size());
- for (size_t i = 0; i < base::size(rects); ++i)
+ ASSERT_EQ(std::size(rects), region_rects.size());
+ for (size_t i = 0; i < std::size(rects); ++i)
EXPECT_EQ(rects[i], region_rects[i]);
}
diff --git a/ui/gfx/platform_font.h b/ui/gfx/platform_font.h
index 6b0025c..ce2f5ab 100644
--- a/ui/gfx/platform_font.h
+++ b/ui/gfx/platform_font.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -25,7 +25,7 @@
// configuration. This allows UI that wants to target a particular size of font
// to obtain that size for the majority of users, while still compensating for a
// user preference for a larger or smaller font.
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
static constexpr int kDefaultBaseFontSize = 13;
#else
static constexpr int kDefaultBaseFontSize = 12;
@@ -33,8 +33,8 @@
// Creates an appropriate PlatformFont implementation.
static PlatformFont* CreateDefault();
-#if defined(OS_APPLE)
- static PlatformFont* CreateFromNativeFont(NativeFont native_font);
+#if BUILDFLAG(IS_APPLE)
+ static PlatformFont* CreateFromCTFont(CTFontRef ct_font);
#endif
// Creates a PlatformFont implementation with the specified |font_name|
// (encoded in UTF-8) and |font_size| in pixels.
@@ -96,18 +96,18 @@
// Returns an object describing how the font should be rendered.
virtual const FontRenderParams& GetFontRenderParams() = 0;
-#if defined(OS_APPLE)
- // Returns the native font handle.
- virtual NativeFont GetNativeFont() const = 0;
+#if BUILDFLAG(IS_APPLE)
+ // Returns the underlying CTFontRef.
+ virtual CTFontRef GetCTFont() const = 0;
#endif
// Returns the underlying Skia typeface. Used in RenderTextHarfBuzz for having
- // access to the exact Skia typeface returned by font fallback, as we would
+ // access to the exact Skia typeface returned by font fallback, as we would
// otherwise lose the handle to the correct platform font instance.
virtual sk_sp<SkTypeface> GetNativeSkTypeface() const = 0;
protected:
- virtual ~PlatformFont() {}
+ virtual ~PlatformFont() = default;
private:
friend class base::RefCounted<PlatformFont>;
diff --git a/ui/gfx/platform_font_ios.h b/ui/gfx/platform_font_ios.h
index 70af745..7186139 100644
--- a/ui/gfx/platform_font_ios.h
+++ b/ui/gfx/platform_font_ios.h
@@ -1,11 +1,11 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_PLATFORM_FONT_IOS_H_
#define UI_GFX_PLATFORM_FONT_IOS_H_
-#include "base/macros.h"
+#include "build/blink_buildflags.h"
#include "ui/gfx/platform_font.h"
namespace gfx {
@@ -13,10 +13,17 @@
class PlatformFontIOS : public PlatformFont {
public:
PlatformFontIOS();
- explicit PlatformFontIOS(NativeFont native_font);
+ explicit PlatformFontIOS(CTFontRef ct_font);
PlatformFontIOS(const std::string& font_name,
int font_size);
-
+#if BUILDFLAG(USE_BLINK)
+ // Constructs a PlatformFontIOS representing the font specified by |typeface|
+ // and the size |font_size_pixels|. Do not call this for a system-specified
+ // font; use the |SystemFontType| constructor for that.
+ PlatformFontIOS(sk_sp<SkTypeface> typeface,
+ int font_size_pixels,
+ const absl::optional<FontRenderParams>& params);
+#endif
PlatformFontIOS(const PlatformFontIOS&) = delete;
PlatformFontIOS& operator=(const PlatformFontIOS&) = delete;
@@ -34,7 +41,7 @@
std::string GetActualFontName() const override;
int GetFontSize() const override;
const FontRenderParams& GetFontRenderParams() override;
- NativeFont GetNativeFont() const override;
+ CTFontRef GetCTFont() const override;
sk_sp<SkTypeface> GetNativeSkTypeface() const override;
private:
diff --git a/ui/gfx/platform_font_ios.mm b/ui/gfx/platform_font_ios.mm
index 5a59235..3d5f90c 100644
--- a/ui/gfx/platform_font_ios.mm
+++ b/ui/gfx/platform_font_ios.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -19,6 +19,20 @@
namespace gfx {
+#if BUILDFLAG(USE_BLINK)
+
+namespace {
+
+std::string GetFamilyNameFromTypeface(sk_sp<SkTypeface> typeface) {
+ SkString family;
+ typeface->getFamilyName(&family);
+ return family.c_str();
+}
+
+} // namespace
+
+#endif
+
////////////////////////////////////////////////////////////////////////////////
// PlatformFontIOS, public:
@@ -31,10 +45,11 @@
CalculateMetrics();
}
-PlatformFontIOS::PlatformFontIOS(NativeFont native_font) {
- std::string font_name = base::SysNSStringToUTF8([native_font fontName]);
- InitWithNameSizeAndStyle(font_name, [native_font pointSize],
- Font::NORMAL, Font::Weight::NORMAL);
+PlatformFontIOS::PlatformFontIOS(CTFontRef ct_font) {
+ UIFont* font = base::mac::CFToNSCast(ct_font);
+ std::string font_name = base::SysNSStringToUTF8([font fontName]);
+ InitWithNameSizeAndStyle(font_name, [font pointSize], Font::NORMAL,
+ Font::Weight::NORMAL);
}
PlatformFontIOS::PlatformFontIOS(const std::string& font_name, int font_size) {
@@ -42,6 +57,18 @@
Font::Weight::NORMAL);
}
+#if BUILDFLAG(USE_BLINK)
+PlatformFontIOS::PlatformFontIOS(
+ sk_sp<SkTypeface> typeface,
+ int font_size_pixels,
+ const absl::optional<FontRenderParams>& params) {
+ InitWithNameSizeAndStyle(GetFamilyNameFromTypeface(typeface),
+ font_size_pixels,
+ (typeface->isItalic() ? Font::ITALIC : Font::NORMAL),
+ FontWeightFromInt(typeface->fontStyle().weight()));
+}
+#endif
+
////////////////////////////////////////////////////////////////////////////////
// PlatformFontIOS, PlatformFont implementation:
@@ -81,7 +108,8 @@
}
std::string PlatformFontIOS::GetActualFontName() const {
- return base::SysNSStringToUTF8([GetNativeFont() familyName]);
+ UIFont* font = base::mac::CFToNSCast(GetCTFont());
+ return base::SysNSStringToUTF8(font.familyName);
}
int PlatformFontIOS::GetFontSize() const {
@@ -94,13 +122,14 @@
return params;
}
-NativeFont PlatformFontIOS::GetNativeFont() const {
- return [UIFont fontWithName:base::SysUTF8ToNSString(font_name_)
- size:font_size_];
+CTFontRef PlatformFontIOS::GetCTFont() const {
+ UIFont* font = [UIFont fontWithName:base::SysUTF8ToNSString(font_name_)
+ size:font_size_];
+ return base::mac::NSToCFCast(font);
}
sk_sp<SkTypeface> PlatformFontIOS::GetNativeSkTypeface() const {
- return SkMakeTypefaceFromCTFont(base::mac::NSToCFCast(GetNativeFont()));
+ return SkMakeTypefaceFromCTFont(GetCTFont());
}
////////////////////////////////////////////////////////////////////////////////
@@ -125,7 +154,7 @@
}
void PlatformFontIOS::CalculateMetrics() {
- UIFont* font = GetNativeFont();
+ UIFont* font = base::mac::CFToNSCast(GetCTFont());
height_ = font.lineHeight;
ascent_ = font.ascender;
cap_height_ = font.capHeight;
@@ -141,8 +170,8 @@
}
// static
-PlatformFont* PlatformFont::CreateFromNativeFont(NativeFont native_font) {
- return new PlatformFontIOS(native_font);
+PlatformFont* PlatformFont::CreateFromCTFont(CTFontRef ct_font) {
+ return new PlatformFontIOS(ct_font);
}
// static
@@ -151,4 +180,16 @@
return new PlatformFontIOS(font_name, font_size);
}
+#if BUILDFLAG(USE_BLINK)
+
+// static
+PlatformFont* PlatformFont::CreateFromSkTypeface(
+ sk_sp<SkTypeface> typeface,
+ int font_size_pixels,
+ const absl::optional<FontRenderParams>& params) {
+ return new PlatformFontIOS(typeface, font_size_pixels, params);
+}
+
+#endif
+
} // namespace gfx
diff --git a/ui/gfx/platform_font_mac.h b/ui/gfx/platform_font_mac.h
index b4e09f6..9320395 100644
--- a/ui/gfx/platform_font_mac.h
+++ b/ui/gfx/platform_font_mac.h
@@ -1,13 +1,13 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_PLATFORM_FONT_MAC_H_
#define UI_GFX_PLATFORM_FONT_MAC_H_
-#include "base/compiler_specific.h"
+#include <CoreText/CoreText.h>
+
#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/font_render_params.h"
#include "ui/gfx/platform_font.h"
@@ -27,10 +27,10 @@
// constructor.
explicit PlatformFontMac(SystemFontType system_font_type);
- // Constructs a PlatformFontMac for containing the NSFont* |native_font|. Do
+ // Constructs a PlatformFontMac for containing the CTFontRef |ct_font|. Do
// not call this for a system-specified font; use the |SystemFontType|
- // constructor for that. |native_font| must not be null.
- explicit PlatformFontMac(NativeFont native_font);
+ // constructor for that. |ct_font| must not be null.
+ explicit PlatformFontMac(CTFontRef ct_font);
// Constructs a PlatformFontMac representing the font with name |font_name|
// and the size |font_size|. Do not call this for a system-specified font; use
@@ -62,11 +62,11 @@
std::string GetActualFontName() const override;
int GetFontSize() const override;
const FontRenderParams& GetFontRenderParams() override;
- NativeFont GetNativeFont() const override;
+ CTFontRef GetCTFont() const override;
sk_sp<SkTypeface> GetNativeSkTypeface() const override;
- // A utility function to get the weight of an NSFont. Used by the unit test.
- static Font::Weight GetFontWeightFromNSFontForTesting(NSFont* font);
+ // A utility function to get the weight of a CTFontRef. Used by the unit test.
+ static Font::Weight GetFontWeightFromCTFontForTesting(CTFontRef font);
private:
struct FontSpec {
@@ -76,10 +76,10 @@
Font::Weight weight;
};
- PlatformFontMac(NativeFont font,
+ PlatformFontMac(CTFontRef font,
absl::optional<SystemFontType> system_font_type);
- PlatformFontMac(NativeFont font,
+ PlatformFontMac(CTFontRef font,
absl::optional<SystemFontType> system_font_type,
FontSpec spec);
@@ -95,7 +95,7 @@
// NSFont instance, this holds that NSFont instance. Otherwise this NSFont
// instance is constructed from the name, size, and style. If there is no
// active font that matched those criteria a default font is used.
- base::scoped_nsobject<NSFont> native_font_;
+ base::scoped_nsobject<NSFont> ns_font_;
// If the font is a system font, and if so, what kind.
const absl::optional<SystemFontType> system_font_type_;
diff --git a/ui/gfx/platform_font_mac.mm b/ui/gfx/platform_font_mac.mm
index 99b4dff..1c56348 100644
--- a/ui/gfx/platform_font_mac.mm
+++ b/ui/gfx/platform_font_mac.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,11 +8,13 @@
#include <set>
#include <Cocoa/Cocoa.h>
+#include <CoreText/CoreText.h>
#import "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#import "base/mac/scoped_nsobject.h"
#include "base/no_destructor.h"
+#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
@@ -33,16 +35,18 @@
// Returns the font style for |font|. Disregards Font::UNDERLINE, since NSFont
// does not support it as a trait.
-int GetFontStyleFromNSFont(NSFont* font) {
+int GetFontStyleFromCTFont(CTFontRef font) {
int font_style = Font::NORMAL;
- NSFontSymbolicTraits traits = [[font fontDescriptor] symbolicTraits];
- if (traits & NSFontItalicTrait)
+ NSFont* ns_font = base::mac::CFToNSCast(font);
+ NSFontSymbolicTraits traits = ns_font.fontDescriptor.symbolicTraits;
+ if (traits & NSFontItalicTrait) {
font_style |= Font::ITALIC;
+ }
return font_style;
}
// Returns the Font::Weight for |font|.
-Weight GetFontWeightFromNSFont(NSFont* font) {
+Weight GetFontWeightFromCTFont(CTFontRef font) {
DCHECK(font);
// Map CoreText weights in a manner similar to ct_weight_to_fontstyle() from
@@ -50,14 +54,14 @@
// system fonts. See PlatformFontMacTest.FontWeightAPIConsistency for details.
// macOS uses specific float values in its constants, but individual fonts can
// and do specify arbitrary values in the -1.0 to 1.0 range. Therefore, to
- // accomodate that, and to avoid float comparison issues, use ranges.
+ // accommodate that, and to avoid float comparison issues, use ranges.
constexpr struct {
// A range of CoreText weights.
CGFloat weight_lower;
CGFloat weight_upper;
Weight gfx_weight;
} weight_map[] = {
- // NSFontWeight constants introduced in 10.11:
+ // NSFontWeight constants:
// NSFontWeightUltraLight: -0.80
// NSFontWeightThin: -0.60
// NSFontWeightLight: -0.40
@@ -69,27 +73,15 @@
// NSFontWeightBlack: 0.62
//
// Actual system font weights:
- // 10.10:
- // .HelveticaNeueDeskInterface-UltraLightP2: -0.80
- // .HelveticaNeueDeskInterface-Thin: -0.50
- // .HelveticaNeueDeskInterface-Light: -0.425
- // .HelveticaNeueDeskInterface-Regular: 0.0
- // .HelveticaNeueDeskInterface-MediumP4: 0.23
- // .HelveticaNeueDeskInterface-Bold (if requested as semibold): 0.24
- // .HelveticaNeueDeskInterface-Bold (if requested as bold): 0.4
- // .HelveticaNeueDeskInterface-Heavy (if requested as heavy): 0.576
- // .HelveticaNeueDeskInterface-Heavy (if requested as black): 0.662
- // 10.11-:
- // .AppleSystemUIFontUltraLight: -0.80
- // .AppleSystemUIFontThin: -0.60
- // .AppleSystemUIFontLight: -0.40
- // .AppleSystemUIFont: 0.0
- // .AppleSystemUIFontMedium: 0.23
- // .AppleSystemUIFontDemi: 0.30
- // .AppleSystemUIFontBold (10.11): 0.40
- // .AppleSystemUIFontEmphasized (10.12-): 0.40
- // .AppleSystemUIFontHeavy: 0.56
- // .AppleSystemUIFontBlack: 0.62
+ // .AppleSystemUIFontUltraLight: -0.80
+ // .AppleSystemUIFontThin: -0.60
+ // .AppleSystemUIFontLight: -0.40
+ // .AppleSystemUIFont: 0.0
+ // .AppleSystemUIFontMedium: 0.23
+ // .AppleSystemUIFontDemi: 0.30
+ // .AppleSystemUIFontEmphasized: 0.40
+ // .AppleSystemUIFontHeavy: 0.56
+ // .AppleSystemUIFontBlack: 0.62
{-1.0, -0.70, Weight::THIN}, // NSFontWeightUltraLight
{-0.70, -0.45, Weight::EXTRA_LIGHT}, // NSFontWeightThin
{-0.45, -0.10, Weight::LIGHT}, // NSFontWeightLight
@@ -101,8 +93,7 @@
{0.60, 1.0, Weight::BLACK}, // NSFontWeightBlack
};
- base::ScopedCFTypeRef<CFDictionaryRef> traits(
- CTFontCopyTraits(base::mac::NSToCFCast(font)));
+ base::ScopedCFTypeRef<CFDictionaryRef> traits(CTFontCopyTraits(font));
DCHECK(traits);
CFNumberRef cf_weight = base::mac::GetValueFromDictionary<CFNumberRef>(
traits, kCTFontWeightTrait);
@@ -110,6 +101,14 @@
if (!cf_weight)
return Weight::NORMAL;
+ // macOS 13.0 bug: For non-system fonts with 0-valued traits,
+ // `kCFBooleanFalse` is used instead of a `CFNumberRef` of 0. See
+ // https://crbug.com/1372420. Filed as FB11673021, fixed in macOS 13.1. In
+ // this code path, the `base::mac::GetValueFromDictionary` call above will
+ // DLOG for this case and return a null `CFNumberRef`, which will cause this
+ // function to return `Weight::NORMAL`, which happens to be the correct thing
+ // to do for a trait with value 0.
+
// The value of kCTFontWeightTrait empirically is a kCFNumberFloat64Type
// (double) on all tested versions of macOS. However, that doesn't really
// matter as only the first two decimal digits need to be tested. Do not check
@@ -202,15 +201,27 @@
return family.c_str();
}
-NSFont* SystemFontForConstructorOfType(PlatformFontMac::SystemFontType type) {
+CTFontRef SystemFontForConstructorOfType(PlatformFontMac::SystemFontType type) {
+ NSFont* font = nil;
switch (type) {
- case PlatformFontMac::SystemFontType::kGeneral:
- return [NSFont systemFontOfSize:[NSFont systemFontSize]];
- case PlatformFontMac::SystemFontType::kMenu:
- return [NSFont menuFontOfSize:0];
- case PlatformFontMac::SystemFontType::kToolTip:
- return [NSFont toolTipsFontOfSize:0];
+ case PlatformFontMac::SystemFontType::kGeneral: {
+ font = [NSFont systemFontOfSize:NSFont.systemFontSize];
+ break;
+ }
+ case PlatformFontMac::SystemFontType::kMenu: {
+ font = [NSFont menuFontOfSize:0];
+ break;
+ }
+ case PlatformFontMac::SystemFontType::kToolTip: {
+ font = [NSFont toolTipsFontOfSize:0];
+ break;
+ }
+ default: {
+ NOTREACHED_NORETURN();
+ }
}
+
+ return base::mac::NSToCFCast(font);
}
absl::optional<PlatformFontMac::SystemFontType>
@@ -268,27 +279,27 @@
: PlatformFontMac(SystemFontForConstructorOfType(system_font_type),
system_font_type) {}
-PlatformFontMac::PlatformFontMac(NativeFont native_font)
- : PlatformFontMac(native_font, absl::nullopt) {
- DCHECK(native_font); // nil should not be passed to this constructor.
+PlatformFontMac::PlatformFontMac(CTFontRef ct_font)
+ : PlatformFontMac(ct_font, absl::nullopt) {
+ DCHECK(ct_font); // nil should not be passed to this constructor.
}
PlatformFontMac::PlatformFontMac(const std::string& font_name, int font_size)
: PlatformFontMac(
- NSFontWithSpec({font_name, font_size, Font::NORMAL, Weight::NORMAL}),
+ base::mac::NSToCFCast(NSFontWithSpec(
+ {font_name, font_size, Font::NORMAL, Weight::NORMAL})),
absl::nullopt,
{font_name, font_size, Font::NORMAL, Weight::NORMAL}) {}
PlatformFontMac::PlatformFontMac(sk_sp<SkTypeface> typeface,
int font_size_pixels,
const absl::optional<FontRenderParams>& params)
- : PlatformFontMac(
- base::mac::CFToNSCast(SkTypeface_GetCTFontRef(typeface.get())),
- SystemFontTypeFromUndocumentedCTFontRefInternals(
- SkTypeface_GetCTFontRef(typeface.get())),
- {GetFamilyNameFromTypeface(typeface), font_size_pixels,
- (typeface->isItalic() ? Font::ITALIC : Font::NORMAL),
- FontWeightFromInt(typeface->fontStyle().weight())}) {}
+ : PlatformFontMac(SkTypeface_GetCTFontRef(typeface.get()),
+ SystemFontTypeFromUndocumentedCTFontRefInternals(
+ SkTypeface_GetCTFontRef(typeface.get())),
+ {GetFamilyNameFromTypeface(typeface), font_size_pixels,
+ (typeface->isItalic() ? Font::ITALIC : Font::NORMAL),
+ FontWeightFromInt(typeface->fontStyle().weight())}) {}
////////////////////////////////////////////////////////////////////////////////
// PlatformFontMac, PlatformFont implementation:
@@ -323,27 +334,27 @@
weight:ToNSFontWeight(weight)];
NSFontTraitMask italic_trait_mask =
(style & Font::ITALIC) ? NSItalicFontMask : NSUnitalicFontMask;
- derived = [[NSFontManager sharedFontManager] convertFont:derived
- toHaveTrait:italic_trait_mask];
+ derived = [NSFontManager.sharedFontManager convertFont:derived
+ toHaveTrait:italic_trait_mask];
return Font(new PlatformFontMac(
- derived, SystemFontType::kGeneral,
+ base::mac::NSToCFCast(derived), SystemFontType::kGeneral,
{font_spec_.name, font_spec_.size + size_delta, style, weight}));
} else if (system_font_type_ == SystemFontType::kMenu) {
NSFont* derived = [NSFont menuFontOfSize:font_spec_.size + size_delta];
return Font(new PlatformFontMac(
- derived, SystemFontType::kMenu,
+ base::mac::NSToCFCast(derived), SystemFontType::kMenu,
{font_spec_.name, font_spec_.size + size_delta, style, weight}));
} else if (system_font_type_ == SystemFontType::kToolTip) {
NSFont* derived = [NSFont toolTipsFontOfSize:font_spec_.size + size_delta];
return Font(new PlatformFontMac(
- derived, SystemFontType::kToolTip,
+ base::mac::NSToCFCast(derived), SystemFontType::kToolTip,
{font_spec_.name, font_spec_.size + size_delta, style, weight}));
} else {
NSFont* derived = NSFontWithSpec(
{font_spec_.name, font_spec_.size + size_delta, style, weight});
return Font(new PlatformFontMac(
- derived, absl::nullopt,
+ base::mac::NSToCFCast(derived), absl::nullopt,
{font_spec_.name, font_spec_.size + size_delta, style, weight}));
}
}
@@ -370,7 +381,7 @@
base::scoped_nsobject<NSAttributedString> attr_string(
[[NSAttributedString alloc]
initWithString:@"abcdefghijklmnopqrstuvwxyz"
- attributes:@{NSFontAttributeName : native_font_.get()}]);
+ attributes:@{NSFontAttributeName : ns_font_.get()}]);
average_width_ = [attr_string size].width / [attr_string length];
DCHECK_NE(0, average_width_);
}
@@ -390,7 +401,7 @@
}
std::string PlatformFontMac::GetActualFontName() const {
- return base::SysNSStringToUTF8([native_font_ familyName]);
+ return base::SysNSStringToUTF8([ns_font_ familyName]);
}
int PlatformFontMac::GetFontSize() const {
@@ -401,37 +412,38 @@
return render_params_;
}
-NativeFont PlatformFontMac::GetNativeFont() const {
- return [[native_font_.get() retain] autorelease];
+CTFontRef PlatformFontMac::GetCTFont() const {
+ return base::mac::NSToCFCast([[ns_font_.get() retain] autorelease]);
}
sk_sp<SkTypeface> PlatformFontMac::GetNativeSkTypeface() const {
- return SkMakeTypefaceFromCTFont(base::mac::NSToCFCast(GetNativeFont()));
+ return SkMakeTypefaceFromCTFont(GetCTFont());
}
// static
-Weight PlatformFontMac::GetFontWeightFromNSFontForTesting(NSFont* font) {
- return GetFontWeightFromNSFont(font);
+Weight PlatformFontMac::GetFontWeightFromCTFontForTesting(CTFontRef font) {
+ return GetFontWeightFromCTFont(font);
}
////////////////////////////////////////////////////////////////////////////////
// PlatformFontMac, private:
PlatformFontMac::PlatformFontMac(
- NativeFont font,
+ CTFontRef ct_font,
absl::optional<SystemFontType> system_font_type)
: PlatformFontMac(
- font,
+ ct_font,
system_font_type,
- {base::SysNSStringToUTF8([font familyName]),
- base::ClampRound([font pointSize]), GetFontStyleFromNSFont(font),
- GetFontWeightFromNSFont(font)}) {}
+ {base::SysNSStringToUTF8(base::mac::CFToNSCast(ct_font).familyName),
+ base::ClampRound(CTFontGetSize(ct_font)),
+ GetFontStyleFromCTFont(ct_font), GetFontWeightFromCTFont(ct_font)}) {
+}
PlatformFontMac::PlatformFontMac(
- NativeFont font,
+ CTFontRef ct_font,
absl::optional<SystemFontType> system_font_type,
FontSpec spec)
- : native_font_([font retain]),
+ : ns_font_([base::mac::CFToNSCast(ct_font) retain]),
system_font_type_(system_font_type),
font_spec_(spec) {
#if DCHECK_IS_ON()
@@ -444,11 +456,10 @@
CalculateMetricsAndInitRenderParams();
}
-PlatformFontMac::~PlatformFontMac() {
-}
+PlatformFontMac::~PlatformFontMac() = default;
void PlatformFontMac::CalculateMetricsAndInitRenderParams() {
- NSFont* font = native_font_.get();
+ NSFont* font = ns_font_.get();
DCHECK(font);
ascent_ = ceil([font ascender]);
cap_height_ = ceil([font capHeight]);
@@ -478,7 +489,7 @@
//
// The way that does work is to use the old-style integer weight API.
- NSFontManager* font_manager = [NSFontManager sharedFontManager];
+ NSFontManager* font_manager = NSFontManager.sharedFontManager;
NSFontTraitMask traits = 0;
if (font_spec.style & Font::ITALIC)
@@ -532,8 +543,8 @@
}
// static
-PlatformFont* PlatformFont::CreateFromNativeFont(NativeFont native_font) {
- return new PlatformFontMac(native_font);
+PlatformFont* PlatformFont::CreateFromCTFont(CTFontRef ct_font) {
+ return new PlatformFontMac(ct_font);
}
// static
diff --git a/ui/gfx/platform_font_mac_unittest.mm b/ui/gfx/platform_font_mac_unittest.mm
index 46b2e6d..aa243a7 100644
--- a/ui/gfx/platform_font_mac_unittest.mm
+++ b/ui/gfx/platform_font_mac_unittest.mm
@@ -1,13 +1,13 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/platform_font_mac.h"
#include <Cocoa/Cocoa.h>
+#include <CoreText/CoreText.h>
#include <stddef.h>
-#include "base/cxx17_backports.h"
#import "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -18,13 +18,34 @@
using Weight = Font::Weight;
TEST(PlatformFontMacTest, DeriveFont) {
+ // macOS 13.0 bug: For non-system fonts with 0-valued traits,
+ // `kCFBooleanFalse` is used instead of a `CFNumberRef` of 0. See
+ // https://crbug.com/1372420. Filed as FB11673021, fixed in macOS 13.1.
+ auto GetValueFromDictionaryAndWorkAroundMacOS13Bug = [](CFDictionaryRef dict,
+ CFStringRef key) {
+ NSOperatingSystemVersion version =
+ [[NSProcessInfo processInfo] operatingSystemVersion];
+
+ if (version.majorVersion == 13 && version.minorVersion == 0) {
+ CFTypeRef value = CFDictionaryGetValue(dict, key);
+ if (value == kCFBooleanFalse) {
+ CGFloat zero = 0;
+ return (CFNumberRef)CFAutorelease(
+ CFNumberCreate(nullptr, kCFNumberCGFloatType, &zero));
+ }
+ }
+
+ return base::mac::GetValueFromDictionary<CFNumberRef>(dict, key);
+ };
+
// |weight_tri| is either -1, 0, or 1 meaning "light", "normal", or "bold".
- auto CheckExpected = [](const Font& font, int weight_tri, bool isItalic) {
+ auto CheckExpected = [GetValueFromDictionaryAndWorkAroundMacOS13Bug](
+ const Font& font, int weight_tri, bool isItalic) {
base::ScopedCFTypeRef<CFDictionaryRef> traits(
- CTFontCopyTraits(base::mac::NSToCFCast(font.GetNativeFont())));
+ CTFontCopyTraits(font.GetCTFont()));
DCHECK(traits);
- CFNumberRef cf_slant = base::mac::GetValueFromDictionary<CFNumberRef>(
+ CFNumberRef cf_slant = GetValueFromDictionaryAndWorkAroundMacOS13Bug(
traits, kCTFontSlantTrait);
CGFloat slant;
CFNumberGetValue(cf_slant, kCFNumberCGFloatType, &slant);
@@ -33,7 +54,7 @@
else
EXPECT_EQ(slant, 0);
- CFNumberRef cf_weight = base::mac::GetValueFromDictionary<CFNumberRef>(
+ CFNumberRef cf_weight = GetValueFromDictionaryAndWorkAroundMacOS13Bug(
traits, kCTFontWeightTrait);
CGFloat weight;
CFNumberGetValue(cf_weight, kCFNumberCGFloatType, &weight);
@@ -97,8 +118,8 @@
base_font.GetWeight()));
// Validate the derived font properties against its native font instance.
- NSFontTraitMask traits = [[NSFontManager sharedFontManager]
- traitsOfFont:derived_font.GetNativeFont()];
+ NSFontTraitMask traits = [NSFontManager.sharedFontManager
+ traitsOfFont:base::mac::CFToNSCast(derived_font.GetCTFont())];
Weight actual_weight =
(traits & NSFontBoldTrait) ? Weight::BOLD : Weight::NORMAL;
@@ -114,38 +135,45 @@
// Tests internal methods for extracting Font properties from the
// underlying CTFont representation.
TEST(PlatformFontMacTest, ConstructFromNativeFont) {
- Font light_font([NSFont fontWithName:@"Helvetica-Light" size:12]);
+ NSFont* ns_light_font = [NSFont fontWithName:@"Helvetica-Light" size:12];
+ Font light_font(base::mac::NSToCFCast(ns_light_font));
EXPECT_EQ(12, light_font.GetFontSize());
EXPECT_EQ("Helvetica", light_font.GetFontName());
EXPECT_EQ(Font::NORMAL, light_font.GetStyle());
EXPECT_EQ(Weight::LIGHT, light_font.GetWeight());
- Font light_italic_font([NSFont fontWithName:@"Helvetica-LightOblique"
- size:14]);
+ NSFont* ns_light_italic_font = [NSFont fontWithName:@"Helvetica-LightOblique"
+ size:14];
+ Font light_italic_font(base::mac::NSToCFCast(ns_light_italic_font));
EXPECT_EQ(14, light_italic_font.GetFontSize());
EXPECT_EQ("Helvetica", light_italic_font.GetFontName());
EXPECT_EQ(Font::ITALIC, light_italic_font.GetStyle());
EXPECT_EQ(Weight::LIGHT, light_italic_font.GetWeight());
- Font normal_font([NSFont fontWithName:@"Helvetica" size:12]);
+ NSFont* ns_normal_font = [NSFont fontWithName:@"Helvetica" size:12];
+ Font normal_font(base::mac::NSToCFCast(ns_normal_font));
EXPECT_EQ(12, normal_font.GetFontSize());
EXPECT_EQ("Helvetica", normal_font.GetFontName());
EXPECT_EQ(Font::NORMAL, normal_font.GetStyle());
EXPECT_EQ(Weight::NORMAL, normal_font.GetWeight());
- Font italic_font([NSFont fontWithName:@"Helvetica-Oblique" size:14]);
+ NSFont* ns_italic_font = [NSFont fontWithName:@"Helvetica-Oblique" size:14];
+ Font italic_font(base::mac::NSToCFCast(ns_italic_font));
EXPECT_EQ(14, italic_font.GetFontSize());
EXPECT_EQ("Helvetica", italic_font.GetFontName());
EXPECT_EQ(Font::ITALIC, italic_font.GetStyle());
EXPECT_EQ(Weight::NORMAL, italic_font.GetWeight());
- Font bold_font([NSFont fontWithName:@"Helvetica-Bold" size:12]);
+ NSFont* ns_bold_font = [NSFont fontWithName:@"Helvetica-Bold" size:12];
+ Font bold_font(base::mac::NSToCFCast(ns_bold_font));
EXPECT_EQ(12, bold_font.GetFontSize());
EXPECT_EQ("Helvetica", bold_font.GetFontName());
EXPECT_EQ(Font::NORMAL, bold_font.GetStyle());
EXPECT_EQ(Weight::BOLD, bold_font.GetWeight());
- Font bold_italic_font([NSFont fontWithName:@"Helvetica-BoldOblique" size:14]);
+ NSFont* ns_bold_italic_font = [NSFont fontWithName:@"Helvetica-BoldOblique"
+ size:14];
+ Font bold_italic_font(base::mac::NSToCFCast(ns_bold_italic_font));
EXPECT_EQ(14, bold_italic_font.GetFontSize());
EXPECT_EQ("Helvetica", bold_italic_font.GetFontName());
EXPECT_EQ(Font::ITALIC, bold_italic_font.GetStyle());
@@ -163,8 +191,8 @@
// interesting.
EXPECT_EQ(static_cast<int>(weight), static_cast<int>(derived.GetWeight()));
- return static_cast<int>(PlatformFontMac::GetFontWeightFromNSFontForTesting(
- derived.GetNativeFont()));
+ return static_cast<int>(PlatformFontMac::GetFontWeightFromCTFontForTesting(
+ derived.GetCTFont()));
};
EXPECT_EQ(static_cast<int>(Weight::THIN), DerivedIntWeight(Weight::THIN));
@@ -184,23 +212,22 @@
// Ensures that the Font's reported height is consistent with the native font's
// ascender and descender metrics.
TEST(PlatformFontMacTest, ValidateFontHeight) {
- // Use the default ResourceBundle system font. E.g. Helvetica Neue in 10.10,
- // Lucida Grande before that, and San Francisco after.
+ // Use the default ResourceBundle system font (i.e. San Francisco).
Font default_font;
Font::FontStyle styles[] = {Font::NORMAL, Font::ITALIC, Font::UNDERLINE};
- for (size_t i = 0; i < base::size(styles); ++i) {
- SCOPED_TRACE(testing::Message() << "Font::FontStyle: " << styles[i]);
+ for (auto& style : styles) {
+ SCOPED_TRACE(testing::Message() << "Font::FontStyle: " << style);
// Include the range of sizes used by ResourceBundle::FontStyle (-1 to +8).
for (int delta = -1; delta <= 8; ++delta) {
- Font font = default_font.Derive(delta, styles[i], Weight::NORMAL);
+ Font font = default_font.Derive(delta, style, Weight::NORMAL);
SCOPED_TRACE(testing::Message() << "FontSize(): " << font.GetFontSize());
- NSFont* native_font = font.GetNativeFont();
+ NSFont* ns_font = base::mac::CFToNSCast(font.GetCTFont());
// Font height (an integer) should be the sum of these.
- CGFloat ascender = [native_font ascender];
- CGFloat descender = [native_font descender];
- CGFloat leading = [native_font leading];
+ CGFloat ascender = ns_font.ascender;
+ CGFloat descender = ns_font.descender;
+ CGFloat leading = ns_font.leading;
// NSFont always gives a negative value for descender. Others positive.
EXPECT_GE(0, descender);
@@ -228,16 +255,14 @@
// system font.
TEST(PlatformFontMacTest, DerivedSemiboldFontIsNotItalic) {
Font base_font;
- {
- NSFontTraitMask traits = [[NSFontManager sharedFontManager]
- traitsOfFont:base_font.GetNativeFont()];
- ASSERT_FALSE(traits & NSItalicFontMask);
- }
+ NSFontTraitMask base_traits = [NSFontManager.sharedFontManager
+ traitsOfFont:base::mac::CFToNSCast(base_font.GetCTFont())];
+ ASSERT_FALSE(base_traits & NSItalicFontMask);
- Font semibold_font(base_font.Derive(0, Font::NORMAL, Weight::SEMIBOLD));
- NSFontTraitMask traits = [[NSFontManager sharedFontManager]
- traitsOfFont:semibold_font.GetNativeFont()];
- EXPECT_FALSE(traits & NSItalicFontMask);
+ Font semibold_font = base_font.Derive(0, Font::NORMAL, Weight::SEMIBOLD);
+ NSFontTraitMask semibold_traits = [NSFontManager.sharedFontManager
+ traitsOfFont:base::mac::CFToNSCast(semibold_font.GetCTFont())];
+ EXPECT_FALSE(semibold_traits & NSItalicFontMask);
}
} // namespace gfx
diff --git a/ui/gfx/platform_font_skia.cc b/ui/gfx/platform_font_skia.cc
index fe80a2c..d418687 100644
--- a/ui/gfx/platform_font_skia.cc
+++ b/ui/gfx/platform_font_skia.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -14,7 +14,6 @@
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
#include "build/build_config.h"
-#include "build/chromeos_buildflags.h"
#include "third_party/skia/include/core/SkFont.h"
#include "third_party/skia/include/core/SkFontMetrics.h"
#include "third_party/skia/include/core/SkFontStyle.h"
@@ -23,20 +22,23 @@
#include "ui/gfx/font.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/font_render_params.h"
-#include "ui/gfx/skia_font_delegate.h"
#include "ui/gfx/text_utils.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "ui/gfx/system_fonts_win.h"
#endif
+#if BUILDFLAG(IS_LINUX)
+#include "ui/linux/linux_ui.h"
+#endif
+
namespace gfx {
namespace {
// The font family name which is used when a user's application font for
// GNOME/KDE is a non-scalable one. The name should be listed in the
// IsFallbackFontAllowed function in skia/ext/SkFontHost_fontconfig_direct.cpp.
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
const char kFallbackFontFamilyName[] = "serif";
#else
const char kFallbackFontFamilyName[] = "sans";
@@ -95,7 +97,7 @@
// PlatformFontSkia, public:
PlatformFontSkia::PlatformFontSkia() {
- CHECK(InitDefaultFont()) << "Could not find the default font";
+ EnsuresDefaultFontIsInitialized();
InitFromPlatformFont(g_default_font.Get().get());
}
@@ -142,18 +144,17 @@
// PlatformFontSkia, PlatformFont implementation:
// static
-bool PlatformFontSkia::InitDefaultFont() {
+void PlatformFontSkia::EnsuresDefaultFontIsInitialized() {
if (g_default_font.Get())
- return true;
+ return;
- bool success = false;
std::string family = kFallbackFontFamilyName;
int size_pixels = PlatformFont::kDefaultBaseFontSize;
int style = Font::NORMAL;
Font::Weight weight = Font::Weight::NORMAL;
FontRenderParams params;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// On windows, the system default font is retrieved by using the GDI API
// SystemParametersInfo(...) (see struct NONCLIENTMETRICS). The font
// properties need to be converted as close as possible to a skia font.
@@ -163,16 +164,20 @@
size_pixels = system_font.GetFontSize();
style = system_font.GetStyle();
weight = system_font.GetWeight();
-#endif // OS_WIN
+#endif // BUILDFLAG(IS_WIN)
- // On Linux, SkiaFontDelegate is used to query the native toolkit (e.g.
- // GTK+) for the default UI font.
- const SkiaFontDelegate* delegate = SkiaFontDelegate::instance();
- if (delegate) {
- delegate->GetDefaultFontDescription(&family, &size_pixels, &style, &weight,
- ¶ms);
- } else if (default_font_description_) {
-#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_CHROMEOS_LACROS)
+#if BUILDFLAG(IS_LINUX)
+ // On Linux, LinuxUi is used to query the native toolkit (e.g.
+ // GTK) for the default UI font.
+ if (const auto* linux_ui = ui::LinuxUi::instance()) {
+ int weight_int;
+ linux_ui->GetDefaultFontDescription(
+ &family, &size_pixels, &style, static_cast<int*>(&weight_int), ¶ms);
+ weight = static_cast<Font::Weight>(weight_int);
+ } else
+#endif
+ if (default_font_description_) {
+#if BUILDFLAG(IS_CHROMEOS)
// On ChromeOS, a FontList font description string is stored as a
// translatable resource and passed in via SetDefaultFontDescription().
FontRenderParamsQuery query;
@@ -191,13 +196,25 @@
params = gfx::GetFontRenderParams(FontRenderParamsQuery(), nullptr);
}
+ bool success = false;
sk_sp<SkTypeface> typeface =
CreateSkTypeface(style & Font::ITALIC, weight, &family, &success);
- if (!success)
- return false;
+
+ // It's possible that the Skia interface is not longer able to proxy queries
+ // to the browser process which make all requests to fail. Calling
+ // MakeDefault() will try to get the default typeface; in case of failure it
+ // returns an instance of SkEmptyTypeface. MakeDefault() should never fail.
+ // See https://crbug.com/1287371 for details.
+ if (!success) {
+ typeface = SkTypeface::MakeDefault();
+ }
+
+ // Ensure there is a typeface available. If none is available, there is
+ // nothing we can do about it and Chrome won't be able to work.
+ CHECK(typeface.get()) << "No typeface available";
+
g_default_font.Get() = new PlatformFontSkia(
std::move(typeface), family, size_pixels, style, weight, params);
- return true;
}
// static
@@ -216,7 +233,7 @@
Font PlatformFontSkia::DeriveFont(int size_delta,
int style,
Font::Weight weight) const {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const int new_size = win::AdjustFontSize(font_size_pixels_, size_delta);
#else
const int new_size = font_size_pixels_ + size_delta;
@@ -341,9 +358,7 @@
&font_family_, &success);
if (!success) {
- LOG(ERROR) << "Could not find any font: " << font_family << ", "
- << kFallbackFontFamilyName << ". Falling back to the default";
-
+ EnsuresDefaultFontIsInitialized();
InitFromPlatformFont(g_default_font.Get().get());
return;
}
@@ -407,7 +422,7 @@
// Linux Skia implements : ceil(-ascent) + ceil(descent)
// TODO(etienneb): Make both implementation consistent and fix the broken
// unittests.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
height_pixels_ = SkScalarCeilToInt(metrics.fDescent - metrics.fAscent);
#else
height_pixels_ = ascent_pixels_ + SkScalarCeilToInt(metrics.fDescent);
diff --git a/ui/gfx/platform_font_skia.h b/ui/gfx/platform_font_skia.h
index 7a92f59..d546232 100644
--- a/ui/gfx/platform_font_skia.h
+++ b/ui/gfx/platform_font_skia.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,8 +8,6 @@
#include <memory>
#include <string>
-#include "base/compiler_specific.h"
-#include "base/macros.h"
#include "build/build_config.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "ui/gfx/font_render_params.h"
@@ -33,10 +31,8 @@
PlatformFontSkia(const PlatformFontSkia&) = delete;
PlatformFontSkia& operator=(const PlatformFontSkia&) = delete;
- // Initials the default PlatformFont. Returns true if this is successful, or
- // false if fonts resources are not available. If this returns false, the
- // calling service should shut down.
- static bool InitDefaultFont();
+ // Initializes the default PlatformFont.
+ static void EnsuresDefaultFontIsInitialized();
// Resets and reloads the cached system font used by the default constructor.
// This function is useful when the system font has changed, for example, when
@@ -66,6 +62,10 @@
const FontRenderParams& GetFontRenderParams() override;
sk_sp<SkTypeface> GetNativeSkTypeface() const override;
+#if BUILDFLAG(IS_APPLE)
+ CTFontRef GetCTFont() const override;
+#endif
+
private:
// Create a new instance of this object with the specified properties. Called
// from DeriveFont.
diff --git a/ui/gfx/platform_font_skia_unittest.cc b/ui/gfx/platform_font_skia_unittest.cc
index 545f3d13..9da0e24 100644
--- a/ui/gfx/platform_font_skia_unittest.cc
+++ b/ui/gfx/platform_font_skia_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,7 +7,7 @@
#include <string>
#include "base/check_op.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/notreached.h"
#include "build/build_config.h"
@@ -15,17 +15,20 @@
#include "ui/gfx/font.h"
#include "ui/gfx/font_names_testing.h"
#include "ui/gfx/font_render_params.h"
-#include "ui/gfx/skia_font_delegate.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include "ui/gfx/system_fonts_win.h"
#endif
+#if BUILDFLAG(IS_LINUX)
+#include "ui/linux/fake_linux_ui.h"
+#endif
+
namespace gfx {
-// Implementation of SkiaFontDelegate used to control the default font
-// description.
-class TestFontDelegate : public SkiaFontDelegate {
+#if BUILDFLAG(IS_LINUX)
+// Implementation of LinuxUi used to control the default font description.
+class TestFontDelegate : public ui::FakeLinuxUi {
public:
TestFontDelegate() = default;
@@ -48,12 +51,12 @@
void GetDefaultFontDescription(std::string* family_out,
int* size_pixels_out,
int* style_out,
- Font::Weight* weight_out,
+ int* weight_out,
FontRenderParams* params_out) const override {
*family_out = family_;
*size_pixels_out = size_pixels_;
*style_out = style_;
- *weight_out = weight_;
+ *weight_out = static_cast<int>(weight_);
*params_out = params_;
}
@@ -76,24 +79,20 @@
~PlatformFontSkiaTest() override = default;
void SetUp() override {
- original_font_delegate_ = SkiaFontDelegate::instance();
- SkiaFontDelegate::SetInstance(&test_font_delegate_);
+ DCHECK_EQ(ui::LinuxUi::instance(), nullptr);
+ old_linux_ui_ = ui::LinuxUi::SetInstance(&test_font_delegate_);
PlatformFontSkia::ReloadDefaultFont();
}
void TearDown() override {
- DCHECK_EQ(&test_font_delegate_, SkiaFontDelegate::instance());
- SkiaFontDelegate::SetInstance(
- const_cast<SkiaFontDelegate*>(original_font_delegate_));
+ DCHECK_EQ(&test_font_delegate_, ui::LinuxUi::instance());
+ ui::LinuxUi::SetInstance(old_linux_ui_);
PlatformFontSkia::ReloadDefaultFont();
}
protected:
TestFontDelegate test_font_delegate_;
-
- private:
- // Originally-registered delegate.
- const SkiaFontDelegate* original_font_delegate_;
+ raw_ptr<ui::LinuxUi> old_linux_ui_ = nullptr;
};
// Test that PlatformFontSkia's default constructor initializes the instance
@@ -126,6 +125,7 @@
EXPECT_NE(font2->GetStyle() & Font::ITALIC, 0);
EXPECT_EQ(gfx::Font::Weight::BOLD, font2->GetWeight());
}
+#endif // BUILDFLAG(IS_LINUX)
TEST(PlatformFontSkiaRenderParamsTest, DefaultFontRenderParams) {
scoped_refptr<PlatformFontSkia> default_font(new PlatformFontSkia());
@@ -138,7 +138,7 @@
named_font->GetFontRenderParams());
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
TEST(PlatformFontSkiaOnWindowsTest, SystemFont) {
// Ensures that the font styles are kept while creating the default font.
gfx::Font system_font = win::GetDefaultSystemFont();
@@ -154,6 +154,6 @@
EXPECT_EQ(system_font.GetFontRenderParams(),
default_font.GetFontRenderParams());
}
-#endif // OS_WIN
+#endif // BUILDFLAG(IS_WIN)
} // namespace gfx
diff --git a/ui/gfx/presentation_feedback.h b/ui/gfx/presentation_feedback.h
index d1b9502..f17416d 100644
--- a/ui/gfx/presentation_feedback.h
+++ b/ui/gfx/presentation_feedback.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,6 +8,8 @@
#include <stdint.h>
#include "base/time/time.h"
+#include "build/build_config.h"
+#include "ui/gfx/ca_layer_result.h"
namespace gfx {
@@ -86,6 +88,10 @@
// The time when write operations have completed, corresponding to the time
// when rendering on the GPU finished.
base::TimeTicks writes_done_timestamp;
+
+#if BUILDFLAG(IS_APPLE)
+ gfx::CALayerResult ca_layer_error_code = gfx::kCALayerSuccess;
+#endif
};
inline bool operator==(const PresentationFeedback& lhs,
@@ -95,6 +101,9 @@
lhs.available_timestamp == rhs.available_timestamp &&
lhs.ready_timestamp == rhs.ready_timestamp &&
lhs.latch_timestamp == rhs.latch_timestamp &&
+#if BUILDFLAG(IS_APPLE)
+ lhs.ca_layer_error_code == rhs.ca_layer_error_code &&
+#endif
lhs.writes_done_timestamp == rhs.writes_done_timestamp;
}
diff --git a/ui/gfx/range/BUILD.gn b/ui/gfx/range/BUILD.gn
index a2e2219..aa17a97 100644
--- a/ui/gfx/range/BUILD.gn
+++ b/ui/gfx/range/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
+# Copyright 2016 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/ui/gfx/range/gfx_range_export.h b/ui/gfx/range/gfx_range_export.h
index dafcefd..db3491e 100644
--- a/ui/gfx/range/gfx_range_export.h
+++ b/ui/gfx/range/gfx_range_export.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/range/mojom/BUILD.gn b/ui/gfx/range/mojom/BUILD.gn
index 3f5fa85..efb6ff0 100644
--- a/ui/gfx/range/mojom/BUILD.gn
+++ b/ui/gfx/range/mojom/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
+# Copyright 2016 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/ui/gfx/range/mojom/range.mojom b/ui/gfx/range/mojom/range.mojom
index 079c146..01869e7 100644
--- a/ui/gfx/range/mojom/range.mojom
+++ b/ui/gfx/range/mojom/range.mojom
@@ -1,14 +1,16 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
module gfx.mojom;
+[Stable]
struct Range {
uint32 start;
uint32 end;
};
+[Stable]
struct RangeF {
float start;
float end;
diff --git a/ui/gfx/range/mojom/range_mojom_traits.h b/ui/gfx/range/mojom/range_mojom_traits.h
index 5db4501..3a1f076 100644
--- a/ui/gfx/range/mojom/range_mojom_traits.h
+++ b/ui/gfx/range/mojom/range_mojom_traits.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -13,8 +13,12 @@
template <>
struct StructTraits<gfx::mojom::RangeDataView, gfx::Range> {
- static uint32_t start(const gfx::Range& r) { return r.start(); }
- static uint32_t end(const gfx::Range& r) { return r.end(); }
+ static uint32_t start(const gfx::Range& r) {
+ return static_cast<uint32_t>(r.start());
+ }
+ static uint32_t end(const gfx::Range& r) {
+ return static_cast<uint32_t>(r.end());
+ }
static bool Read(gfx::mojom::RangeDataView data, gfx::Range* out) {
out->set_start(data.start());
out->set_end(data.end());
diff --git a/ui/gfx/range/mojom/range_mojom_traits_unittest.cc b/ui/gfx/range/mojom/range_mojom_traits_unittest.cc
index ba49cb8..e92f85b 100644
--- a/ui/gfx/range/mojom/range_mojom_traits_unittest.cc
+++ b/ui/gfx/range/mojom/range_mojom_traits_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -46,14 +46,17 @@
} // namespace
TEST_F(RangeStructTraitsTest, Range) {
- const uint32_t start = 1234;
- const uint32_t end = 5678;
+ const size_t start = 1234;
+ const size_t end = 5678;
gfx::Range input(start, end);
mojo::Remote<mojom::RangeTraitsTestService> remote = GetTraitsTestRemote();
gfx::Range output;
remote->EchoRange(input, &output);
EXPECT_EQ(start, output.start());
EXPECT_EQ(end, output.end());
+
+ remote->EchoRange(gfx::Range::InvalidRange(), &output);
+ EXPECT_FALSE(output.IsValid());
}
TEST_F(RangeStructTraitsTest, RangeF) {
diff --git a/ui/gfx/range/mojom/range_traits_test_service.mojom b/ui/gfx/range/mojom/range_traits_test_service.mojom
index 7a0f7a9..26f38ee 100644
--- a/ui/gfx/range/mojom/range_traits_test_service.mojom
+++ b/ui/gfx/range/mojom/range_traits_test_service.mojom
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/range/range.cc b/ui/gfx/range/range.cc
index 2776f3d..a06c2e3 100644
--- a/ui/gfx/range/range.cc
+++ b/ui/gfx/range/range.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,14 +6,13 @@
#include <inttypes.h>
-#include <algorithm>
-
+#include "base/format_macros.h"
#include "base/strings/stringprintf.h"
namespace gfx {
std::string Range::ToString() const {
- return base::StringPrintf("{%" PRIu32 ",%" PRIu32 "}", start(), end());
+ return base::StringPrintf("{%" PRIuS ",%" PRIuS "}", start(), end());
}
std::ostream& operator<<(std::ostream& os, const Range& range) {
diff --git a/ui/gfx/range/range.h b/ui/gfx/range/range.h
index b2f6cc4..c42d20f 100644
--- a/ui/gfx/range/range.h
+++ b/ui/gfx/range/range.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,20 +8,22 @@
#include <stddef.h>
#include <stdint.h>
+#include <algorithm>
#include <limits>
#include <ostream>
#include <string>
+#include "base/numerics/safe_conversions.h"
#include "build/build_config.h"
#include "ui/gfx/range/gfx_range_export.h"
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#if __OBJC__
#import <Foundation/Foundation.h>
#else
typedef struct _NSRange NSRange;
#endif
-#endif // defined(OS_APPLE)
+#endif // BUILDFLAG(IS_APPLE)
namespace gfx {
@@ -36,14 +38,21 @@
constexpr Range() : Range(0) {}
// Initializes the range with a start and end.
- constexpr Range(uint32_t start, uint32_t end) : start_(start), end_(end) {}
+ constexpr Range(size_t start, size_t end)
+ : start_(base::checked_cast<uint32_t>(start)),
+ end_(base::checked_cast<uint32_t>(end)) {}
// Initializes the range with the same start and end positions.
- constexpr explicit Range(uint32_t position) : Range(position, position) {}
+ constexpr explicit Range(size_t position) : Range(position, position) {}
// Platform constructors.
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
+ // Constructs a Range from a NSRange.
+ // CHECKs if NSRange is out of the maximum bound of Range.
explicit Range(const NSRange& range);
+ // Constructs a Range from a NSRange.
+ // Returns InvalidRange() if NSRange is out of the maximum bound of Range.
+ static Range FromPossiblyInvalidNSRange(const NSRange& range);
#endif
// Returns a range that is invalid, which is {UINT32_MAX,UINT32_MAX}.
@@ -51,27 +60,28 @@
return Range(std::numeric_limits<uint32_t>::max());
}
- // Checks if the range is valid through comparison to InvalidRange().
+ // Checks if the range is valid through comparison to InvalidRange(). If this
+ // is not valid, you must not call start()/end().
constexpr bool IsValid() const { return *this != InvalidRange(); }
// Getters and setters.
- constexpr uint32_t start() const { return start_; }
- void set_start(uint32_t start) { start_ = start; }
+ constexpr size_t start() const { return start_; }
+ void set_start(size_t start) { start_ = base::checked_cast<uint32_t>(start); }
- constexpr uint32_t end() const { return end_; }
- void set_end(uint32_t end) { end_ = end; }
+ constexpr size_t end() const { return end_; }
+ void set_end(size_t end) { end_ = base::checked_cast<uint32_t>(end); }
// Returns the absolute value of the length.
- constexpr uint32_t length() const { return GetMax() - GetMin(); }
+ constexpr size_t length() const { return GetMax() - GetMin(); }
constexpr bool is_reversed() const { return start() > end(); }
constexpr bool is_empty() const { return start() == end(); }
// Returns the minimum and maximum values.
- constexpr uint32_t GetMin() const {
+ constexpr size_t GetMin() const {
return start() < end() ? start() : end();
}
- constexpr uint32_t GetMax() const {
+ constexpr size_t GetMax() const {
return start() > end() ? start() : end();
}
@@ -108,14 +118,16 @@
// If they don't intersect, it returns an InvalidRange().
// The returned range is always empty or forward (never reversed).
constexpr Range Intersect(const Range& range) const {
- const uint32_t min = std::max(GetMin(), range.GetMin());
- const uint32_t max = std::min(GetMax(), range.GetMax());
+ const size_t min = std::max(GetMin(), range.GetMin());
+ const size_t max = std::min(GetMax(), range.GetMax());
return (min < max || Contains(range) || range.Contains(*this))
? Range(min, max)
: InvalidRange();
}
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
+ // Constructs a Range from a NSRange.
+ // CHECKs if NSRange is out of the maximum bound of Range.
Range& operator=(const NSRange& range);
// NSRange does not store the directionality of a range, so if this
@@ -128,8 +140,7 @@
private:
// Note: we use uint32_t instead of size_t because this struct is sent over
- // IPC which could span 32 & 64 bit processes. This is fine since text spans
- // shouldn't exceed UINT32_MAX even on 64 bit builds.
+ // IPC which could span 32 & 64 bit processes.
uint32_t start_;
uint32_t end_;
};
diff --git a/ui/gfx/range/range_f.cc b/ui/gfx/range/range_f.cc
index f3af360..89f30b8 100644
--- a/ui/gfx/range/range_f.cc
+++ b/ui/gfx/range/range_f.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/range/range_f.h b/ui/gfx/range/range_f.h
index 1d51b29..cbe7231 100644
--- a/ui/gfx/range/range_f.h
+++ b/ui/gfx/range/range_f.h
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/range/range_mac.mm b/ui/gfx/range/range_mac.mm
index cc1aa1e..4d4dbc9 100644
--- a/ui/gfx/range/range_mac.mm
+++ b/ui/gfx/range/range_mac.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,6 +9,7 @@
#include <limits>
#include "base/check_op.h"
+#include "base/numerics/checked_math.h"
namespace gfx {
@@ -16,14 +17,25 @@
*this = range;
}
+Range Range::FromPossiblyInvalidNSRange(const NSRange& range) {
+ uint32_t end;
+ if (range.location == NSNotFound ||
+ !base::IsValueInRangeForNumericType<uint32_t>(range.location) ||
+ !base::IsValueInRangeForNumericType<uint32_t>(range.length) ||
+ !base::CheckAdd<uint32_t>(range.location, range.length)
+ .AssignIfValid(&end)) {
+ return InvalidRange();
+ }
+
+ return Range(range.location, end);
+}
+
Range& Range::operator=(const NSRange& range) {
if (range.location == NSNotFound) {
DCHECK_EQ(0U, range.length);
*this = InvalidRange();
} else {
set_start(range.location);
- // Don't overflow |end_|.
- DCHECK_LE(range.length, std::numeric_limits<size_t>::max() - start());
set_end(start() + range.length);
}
return *this;
diff --git a/ui/gfx/range/range_mac_unittest.mm b/ui/gfx/range/range_mac_unittest.mm
index 85323f2..ddf9c29 100644
--- a/ui/gfx/range/range_mac_unittest.mm
+++ b/ui/gfx/range/range_mac_unittest.mm
@@ -1,10 +1,13 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/range/range.h"
+#include <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
TEST(RangeTest, FromNSRange) {
NSRange nsr = NSMakeRange(10, 3);
gfx::Range r(nsr);
@@ -41,3 +44,18 @@
EXPECT_EQ(static_cast<NSUInteger>(NSNotFound), nsr.location);
EXPECT_EQ(0U, nsr.length);
}
+
+TEST(RangeTest, FromPossiblyInvalidNSRange) {
+ constexpr uint32_t range_max = std::numeric_limits<uint32_t>::max();
+ EXPECT_NE(
+ gfx::Range::FromPossiblyInvalidNSRange(NSMakeRange(range_max - 1, 1)),
+ gfx::Range::InvalidRange());
+ EXPECT_EQ(gfx::Range::FromPossiblyInvalidNSRange(NSMakeRange(range_max, 1)),
+ gfx::Range::InvalidRange());
+ EXPECT_EQ(gfx::Range::FromPossiblyInvalidNSRange(
+ NSMakeRange(static_cast<int64_t>(range_max) + 1, 0)),
+ gfx::Range::InvalidRange());
+ EXPECT_EQ(gfx::Range::FromPossiblyInvalidNSRange(
+ NSMakeRange(0, static_cast<int64_t>(range_max) + 1)),
+ gfx::Range::InvalidRange());
+}
diff --git a/ui/gfx/range/range_unittest.cc b/ui/gfx/range/range_unittest.cc
index 8fba740..088c583 100644
--- a/ui/gfx/range/range_unittest.cc
+++ b/ui/gfx/range/range_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc
index 99120dd..17d8659 100644
--- a/ui/gfx/render_text.cc
+++ b/ui/gfx/render_text.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,11 +11,11 @@
#include "base/check_op.h"
#include "base/command_line.h"
-#include "base/cxx17_backports.h"
#include "base/i18n/break_iterator.h"
#include "base/i18n/char_iterator.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
+#include "base/ranges/algorithm.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
@@ -42,10 +42,6 @@
#include "ui/gfx/text_utils.h"
#include "ui/gfx/utf16_indexing.h"
-#if defined(OS_WIN)
-#include "base/win/windows_version.h"
-#endif
-
namespace gfx {
namespace {
@@ -144,9 +140,15 @@
const SkPoint points[2] = { PointToSkPoint(text_rect.origin()),
PointToSkPoint(text_rect.top_right()) };
+ // TODO(crbug/1308932): Remove this helper vector colors4f and make all
+ // SkColor4f.
+ std::vector<SkColor4f> colors4f;
+ colors4f.reserve(colors.size());
+ for (auto& c : colors)
+ colors4f.push_back(SkColor4f::FromColor(c));
return cc::PaintShader::MakeLinearGradient(
- &points[0], &colors[0], &positions[0], static_cast<int>(colors.size()),
- SkTileMode::kClamp);
+ &points[0], &colors4f[0], &positions[0],
+ static_cast<int>(colors4f.size()), SkTileMode::kClamp);
}
// Converts a FontRenderParams::Hinting value to the corresponding
@@ -191,12 +193,14 @@
const BreakList<T>& break_list,
typename BreakList<T>::const_iterator iter,
size_t position) {
- for (; iter != break_list.breaks().end(); ++iter) {
+ DCHECK_LT(position, break_list.max());
+ for (;;) {
+ CHECK(iter != break_list.breaks().end());
const Range range = break_list.GetRange(iter);
if (position >= range.start() && position < range.end())
- break;
+ return iter;
+ ++iter;
}
- return iter;
}
// Replaces the unicode control characters, control characters and PUA (Private
@@ -210,9 +214,18 @@
constexpr char16_t kSymbolsCodepoint = 0x2400;
if (codepoint >= 0 && codepoint <= 0x1F) {
- // Replace codepoints with their visual symbols, which are
- // at the same offset from kSymbolsCodepoint.
- return kSymbolsCodepoint + codepoint;
+ switch (codepoint) {
+ case 0x09:
+ // Replace character tabulation ('\t') with its visual arrow symbol.
+ return 0x21E5;
+ case 0x0A:
+ // Replace line feed ('\n') with space character.
+ return 0x20;
+ default:
+ // Replace codepoints with their visual symbols, which are
+ // at the same offset from kSymbolsCodepoint.
+ return kSymbolsCodepoint + codepoint;
+ }
}
if (codepoint == 0x7F) {
// Replace the 'del' codepoint by its symbol (u2421).
@@ -230,35 +243,33 @@
if (codepoint > 0x7F) {
// Private use codepoints are working with a pair of font
// and codepoint, but they are not used in Chrome.
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
// Support Apple defined PUA on Mac.
// see: http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/CORPCHAR.TXT
if (codepoint == 0xF8FF)
return codepoint;
#endif
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Support Microsoft defined PUA on Windows.
// see:
// https://docs.microsoft.com/en-us/windows/uwp/design/style/segoe-ui-symbol-font
- if (base::win::GetVersion() >= base::win::Version::WIN10) {
- switch (codepoint) {
- case 0xF093: // ButtonA
- case 0xF094: // ButtonB
- case 0xF095: // ButtonY
- case 0xF096: // ButtonX
- case 0xF108: // LeftStick
- case 0xF109: // RightStick
- case 0xF10A: // TriggerLeft
- case 0xF10B: // TriggerRight
- case 0xF10C: // BumperLeft
- case 0xF10D: // BumperRight
- case 0xF10E: // Dpad
- case 0xEECA: // ButtonView2
- case 0xEDE3: // ButtonMenu
- return codepoint;
- default:
- break;
- }
+ switch (codepoint) {
+ case 0xF093: // ButtonA
+ case 0xF094: // ButtonB
+ case 0xF095: // ButtonY
+ case 0xF096: // ButtonX
+ case 0xF108: // LeftStick
+ case 0xF109: // RightStick
+ case 0xF10A: // TriggerLeft
+ case 0xF10B: // TriggerRight
+ case 0xF10C: // BumperLeft
+ case 0xF10D: // BumperRight
+ case 0xF10E: // Dpad
+ case 0xEECA: // ButtonView2
+ case 0xEDE3: // ButtonMenu
+ return codepoint;
+ default:
+ break;
}
#endif
const int8_t codepoint_category = u_charType(codepoint);
@@ -517,7 +528,7 @@
if (directionality_mode_ == DIRECTIONALITY_FROM_TEXT)
text_direction_ = base::i18n::UNKNOWN_DIRECTION;
- obscured_reveal_index_ = -1;
+ obscured_reveal_index_ = absl::nullopt;
OnTextAttributeChanged();
}
@@ -525,7 +536,7 @@
text_ += text;
UpdateStyleLengths();
cached_bounds_and_offset_valid_ = false;
- obscured_reveal_index_ = -1;
+ obscured_reveal_index_ = absl::nullopt;
// Invalidate the cached text direction if it depends on the text contents.
if (directionality_mode_ == DIRECTIONALITY_FROM_TEXT)
@@ -563,20 +574,22 @@
}
void RenderText::SetCursorEnabled(bool cursor_enabled) {
- cursor_enabled_ = cursor_enabled;
- cached_bounds_and_offset_valid_ = false;
+ if (cursor_enabled_ != cursor_enabled) {
+ cursor_enabled_ = cursor_enabled;
+ cached_bounds_and_offset_valid_ = false;
+ }
}
void RenderText::SetObscured(bool obscured) {
if (obscured != obscured_) {
obscured_ = obscured;
- obscured_reveal_index_ = -1;
+ obscured_reveal_index_ = absl::nullopt;
cached_bounds_and_offset_valid_ = false;
OnTextAttributeChanged();
}
}
-void RenderText::SetObscuredRevealIndex(int index) {
+void RenderText::SetObscuredRevealIndex(absl::optional<size_t> index) {
if (obscured_reveal_index_ != index) {
obscured_reveal_index_ = index;
cached_bounds_and_offset_valid_ = false;
@@ -600,8 +613,10 @@
}
void RenderText::SetMaxLines(size_t max_lines) {
- max_lines_ = max_lines;
- OnDisplayTextAttributeChanged();
+ if (max_lines_ != max_lines) {
+ max_lines_ = max_lines;
+ OnDisplayTextAttributeChanged();
+ }
}
size_t RenderText::GetNumLines() {
@@ -769,7 +784,7 @@
bool RenderText::SetSelection(const SelectionModel& model) {
// Enforce valid selection model components.
- uint32_t text_length = static_cast<uint32_t>(text().length());
+ size_t text_length = text().length();
std::vector<Range> ranges = model.GetAllSelections();
for (auto& range : ranges) {
range = {std::min(range.start(), text_length),
@@ -795,7 +810,7 @@
}
bool RenderText::SelectRange(const Range& range, bool primary) {
- uint32_t text_length = static_cast<uint32_t>(text().length());
+ size_t text_length = text().length();
Range sel(std::min(range.start(), text_length),
std::min(range.end(), text_length));
// Allow selection bounds at valid indices amid multi-character graphemes.
@@ -845,61 +860,61 @@
}
void RenderText::SetColor(SkColor value) {
- colors_.SetValue(value);
- OnLayoutTextAttributeChanged(false);
+ if (colors_.SetValue(value))
+ OnLayoutTextAttributeChanged(false);
}
void RenderText::ApplyColor(SkColor value, const Range& range) {
- colors_.ApplyValue(value, range);
- OnLayoutTextAttributeChanged(false);
+ if (colors_.ApplyValue(value, range))
+ OnLayoutTextAttributeChanged(false);
}
void RenderText::SetBaselineStyle(BaselineStyle value) {
- baselines_.SetValue(value);
- OnLayoutTextAttributeChanged(false);
+ if (baselines_.SetValue(value))
+ OnLayoutTextAttributeChanged(false);
}
void RenderText::ApplyBaselineStyle(BaselineStyle value, const Range& range) {
- baselines_.ApplyValue(value, range);
- OnLayoutTextAttributeChanged(false);
+ if (baselines_.ApplyValue(value, range))
+ OnLayoutTextAttributeChanged(false);
}
void RenderText::ApplyFontSizeOverride(int font_size_override,
const Range& range) {
- font_size_overrides_.ApplyValue(font_size_override, range);
- OnLayoutTextAttributeChanged(false);
+ if (font_size_overrides_.ApplyValue(font_size_override, range))
+ OnLayoutTextAttributeChanged(false);
}
void RenderText::SetStyle(TextStyle style, bool value) {
- styles_[style].SetValue(value);
-
- cached_bounds_and_offset_valid_ = false;
- // TODO(oshima|msw): Not all style change requires layout changes.
- // Consider optimizing based on the type of change.
- OnLayoutTextAttributeChanged(false);
+ if (styles_[style].SetValue(value)) {
+ cached_bounds_and_offset_valid_ = false;
+ // TODO(oshima|msw): Not all style change requires layout changes.
+ // Consider optimizing based on the type of change.
+ OnLayoutTextAttributeChanged(false);
+ }
}
void RenderText::ApplyStyle(TextStyle style, bool value, const Range& range) {
- styles_[style].ApplyValue(value, range);
-
- cached_bounds_and_offset_valid_ = false;
- // TODO(oshima|msw): Not all style change requires layout changes.
- // Consider optimizing based on the type of change.
- OnLayoutTextAttributeChanged(false);
+ if (styles_[style].ApplyValue(value, range)) {
+ cached_bounds_and_offset_valid_ = false;
+ // TODO(oshima|msw): Not all style change requires layout changes.
+ // Consider optimizing based on the type of change.
+ OnLayoutTextAttributeChanged(false);
+ }
}
void RenderText::SetWeight(Font::Weight weight) {
- weights_.SetValue(weight);
-
- cached_bounds_and_offset_valid_ = false;
- OnLayoutTextAttributeChanged(false);
+ if (weights_.SetValue(weight)) {
+ cached_bounds_and_offset_valid_ = false;
+ OnLayoutTextAttributeChanged(false);
+ }
}
void RenderText::ApplyWeight(Font::Weight weight, const Range& range) {
- weights_.ApplyValue(weight, range);
-
- cached_bounds_and_offset_valid_ = false;
- OnLayoutTextAttributeChanged(false);
+ if (weights_.ApplyValue(weight, range)) {
+ cached_bounds_and_offset_valid_ = false;
+ OnLayoutTextAttributeChanged(false);
+ }
}
bool RenderText::GetStyle(TextStyle style) const {
@@ -965,8 +980,13 @@
int RenderText::GetBaseline() {
if (baseline_ == kInvalidBaseline) {
- baseline_ =
- DetermineBaselineCenteringText(display_rect().height(), font_list());
+ const int centering_height =
+ (vertical_alignment_ == ALIGN_MIDDLE)
+ ? display_rect().height()
+ : std::max(font_list().GetHeight(), min_line_height());
+ baseline_ = DetermineBaselineCenteringText(centering_height, font_list());
+ if (vertical_alignment_ == ALIGN_BOTTOM)
+ baseline_ += display_rect().height() - centering_height;
}
DCHECK_NE(kInvalidBaseline, baseline_);
return baseline_;
@@ -1229,7 +1249,11 @@
}
void RenderText::SetDisplayOffset(Vector2d offset) {
- const int extra_content = GetContentWidth() - display_rect_.width();
+ // Use ClampedNumeric for extra content, as it can otherwise overflow during
+ // later operations if GetContentWidth() returns INT_MAX and
+ // display_rect_.width() is 0.
+ const base::ClampedNumeric<int> extra_content =
+ base::ClampedNumeric<int>(GetContentWidth()) - display_rect_.width();
const int cursor_width = cursor_enabled_ ? 1 : 0;
int min_offset = 0;
@@ -1255,12 +1279,12 @@
}
}
- const int horizontal_offset = base::clamp(offset.x(), min_offset, max_offset);
+ const int horizontal_offset = std::clamp(offset.x(), min_offset, max_offset);
// y-offset is set only when the vertical alignment is ALIGN_TOP.
// TODO(jongkown.lee): Support other vertical alignments.
DCHECK(vertical_alignment_ == ALIGN_TOP || offset.y() == 0);
- const int vertical_offset = base::clamp(
+ const int vertical_offset = std::clamp(
offset.y(),
std::min(display_rect_.height() - GetStringSize().height(), 0), 0);
@@ -1347,6 +1371,46 @@
: Range(min_index, max_index);
}
+Range RenderText::ExpandRangeToWordBoundary(const Range& range) const {
+ const size_t length = text().length();
+ DCHECK_LE(range.GetMax(), length);
+ if (obscured()) {
+ return range.is_reversed() ? Range(length, 0) : Range(0, length);
+ }
+
+ base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
+ const bool success = iter.Init();
+ DCHECK(success);
+ if (!success) {
+ return range;
+ }
+
+ size_t range_min = range.GetMin();
+ if (range_min == length && range_min != 0) {
+ --range_min;
+ }
+
+ for (; range_min != 0; --range_min) {
+ if (iter.IsStartOfWord(range_min) || iter.IsEndOfWord(range_min)) {
+ break;
+ }
+ }
+
+ size_t range_max = range.GetMax();
+ if (range_min == range_max && range_max != length) {
+ ++range_max;
+ }
+
+ for (; range_max < length; ++range_max) {
+ if (iter.IsEndOfWord(range_max) || iter.IsStartOfWord(range_max)) {
+ break;
+ }
+ }
+
+ return range.is_reversed() ? Range(range_max, range_min)
+ : Range(range_min, range_max);
+}
+
bool RenderText::IsNewlineSegment(const internal::LineSegment& segment) const {
return IsNewlineSegment(text_, segment);
}
@@ -1404,9 +1468,8 @@
return false;
}
- return std::none_of(
- styles().cbegin(), styles().cend(),
- [](const auto& style) { return style.breaks().size() > 1; });
+ return base::ranges::none_of(
+ styles(), [](const auto& style) { return style.breaks().size() > 1; });
}
internal::ShapedText* RenderText::GetShapedText() {
@@ -1520,8 +1583,8 @@
// Ensures the reveal index is at a codepoint boundary (e.g. not in a middle
// of a surrogate pairs).
size_t reveal_index = text_.size();
- if (obscured_reveal_index_ != -1) {
- reveal_index = base::checked_cast<size_t>(obscured_reveal_index_);
+ if (obscured_reveal_index_.has_value()) {
+ reveal_index = obscured_reveal_index_.value();
// Move |reveal_index| to the beginning of the surrogate pair, if needed.
if (reveal_index < text_.size())
U16_SET_CP_START(text_.data(), 0, reveal_index);
@@ -1662,7 +1725,6 @@
static_cast<float>(display_rect_.width()),
elide_behavior_));
} else {
- bool was_elided = text_elided_;
text_elided_ = false;
display_text_.clear();
@@ -1687,12 +1749,7 @@
Elide(text_to_elide, 0,
static_cast<float>(display_rect_.width()),
ELIDE_TAIL));
- // Have GetLineBreaks() re-calculate.
- line_breaks_.SetMax(0);
} else {
- // If elision changed, re-calculate.
- if (was_elided)
- line_breaks_.SetMax(0);
// Initial state above is fine.
return;
}
@@ -1702,26 +1759,6 @@
display_text_.clear();
}
-const BreakList<size_t>& RenderText::GetLineBreaks() {
- if (line_breaks_.max() != 0)
- return line_breaks_;
-
- const std::u16string& layout_text = GetDisplayText();
- const size_t text_length = layout_text.length();
- line_breaks_.SetValue(0);
- line_breaks_.SetMax(text_length);
- base::i18n::BreakIterator iter(layout_text,
- base::i18n::BreakIterator::BREAK_LINE);
- const bool success = iter.Init();
- DCHECK(success);
- if (success) {
- do {
- line_breaks_.ApplyValue(iter.pos(), Range(iter.pos(), text_length));
- } while (iter.Advance());
- }
- return line_breaks_;
-}
-
Point RenderText::ToViewPoint(const PointF& point, size_t line) {
if (GetNumLines() == 1) {
return Point(base::ClampCeil(Clamp(point.x())),
@@ -1769,11 +1806,12 @@
HorizontalAlignment horizontal_alignment = GetCurrentHorizontalAlignment();
if (horizontal_alignment != ALIGN_LEFT) {
const int width =
- multiline_
- ? std::ceil(GetShapedText()->lines()[line_number].size.width()) +
- (cursor_enabled_ ? 1 : 0)
- : GetContentWidth();
+ multiline_ ? base::ClampCeil(
+ GetShapedText()->lines()[line_number].size.width() +
+ (cursor_enabled_ ? 1.0f : 0.0f))
+ : GetContentWidth();
offset.set_x(display_rect().width() - width);
+
// Put any extra margin pixel on the left to match legacy behavior.
if (horizontal_alignment == ALIGN_CENTER)
offset.set_x((offset.x() + 1) / 2);
@@ -1812,13 +1850,15 @@
Rect right_part;
if (horizontal_alignment != ALIGN_LEFT) {
left_part = solid_part;
- left_part.Inset(0, 0, solid_part.width() - gradient_width, 0);
- solid_part.Inset(gradient_width, 0, 0, 0);
+ left_part.Inset(
+ gfx::Insets::TLBR(0, 0, 0, solid_part.width() - gradient_width));
+ solid_part.Inset(gfx::Insets::TLBR(0, gradient_width, 0, 0));
}
if (horizontal_alignment != ALIGN_RIGHT) {
right_part = solid_part;
- right_part.Inset(solid_part.width() - gradient_width, 0, 0, 0);
- solid_part.Inset(0, 0, gradient_width, 0);
+ right_part.Inset(
+ gfx::Insets::TLBR(0, solid_part.width() - gradient_width, 0, 0));
+ solid_part.Inset(gfx::Insets::TLBR(0, 0, 0, gradient_width));
}
// CreateFadeShader() expects at least one part to not be empty.
@@ -1827,7 +1867,7 @@
return;
Rect text_rect = display_rect();
- text_rect.Inset(GetAlignmentOffset(0).x(), 0, 0, 0);
+ text_rect.Inset(gfx::Insets::TLBR(0, GetAlignmentOffset(0).x(), 0, 0));
// TODO(msw): Use the actual text colors corresponding to each faded part.
renderer->SetShader(
@@ -1918,7 +1958,8 @@
bool RenderText::RangeContainsCaret(const Range& range,
size_t caret_pos,
LogicalCursorDirection caret_affinity) {
- // NB: exploits unsigned wraparound (WG14/N1124 section 6.2.5 paragraph 9).
+ if (caret_pos == 0 && caret_affinity == CURSOR_BACKWARD)
+ return false;
size_t adjacent = (caret_affinity == CURSOR_BACKWARD) ?
caret_pos - 1 : caret_pos + 1;
return range.Contains(Range(caret_pos, adjacent));
@@ -1943,7 +1984,7 @@
const int space =
display_height - ((internal_leading != 0) ? cap_height : font_height);
const int baseline_shift = space / 2 - internal_leading;
- return baseline + base::clamp(baseline_shift, min_shift, max_shift);
+ return baseline + std::clamp(baseline_shift, min_shift, max_shift);
}
// static
@@ -1990,7 +2031,6 @@
layout_text_.clear();
display_text_.clear();
text_elided_ = false;
- line_breaks_.SetMax(0);
layout_text_up_to_date_ = false;
@@ -2059,7 +2099,7 @@
guess = lo + base::ClampRound<size_t>((available_width - lo_width) *
(hi - lo) / (hi_width - lo_width));
}
- guess = base::clamp(guess, lo, hi);
+ guess = std::clamp(guess, lo, hi);
DCHECK_NE(last_guess, guess);
// Restore colors. They will be truncated to size by SetText.
@@ -2316,36 +2356,4 @@
return length;
}
-Range RenderText::ExpandRangeToWordBoundary(const Range& range) const {
- const size_t length = text().length();
- DCHECK_LE(range.GetMax(), length);
- if (obscured())
- return range.is_reversed() ? Range(length, 0) : Range(0, length);
-
- base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
- const bool success = iter.Init();
- DCHECK(success);
- if (!success)
- return range;
-
- size_t range_min = range.GetMin();
- if (range_min == length && range_min != 0)
- --range_min;
-
- for (; range_min != 0; --range_min)
- if (iter.IsStartOfWord(range_min) || iter.IsEndOfWord(range_min))
- break;
-
- size_t range_max = range.GetMax();
- if (range_min == range_max && range_max != length)
- ++range_max;
-
- for (; range_max < length; ++range_max)
- if (iter.IsEndOfWord(range_max) || iter.IsStartOfWord(range_max))
- break;
-
- return range.is_reversed() ? Range(range_max, range_min)
- : Range(range_min, range_max);
-}
-
} // namespace gfx
diff --git a/ui/gfx/render_text.h b/ui/gfx/render_text.h
index bb01b82..3c78525 100644
--- a/ui/gfx/render_text.h
+++ b/ui/gfx/render_text.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -17,10 +17,10 @@
#include <vector>
#include "base/i18n/rtl.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
-#include "cc/paint/paint_canvas.h"
#include "cc/paint/paint_flags.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkFont.h"
#include "third_party/skia/include/core/SkRefCnt.h"
@@ -43,6 +43,10 @@
struct SkPoint;
class SkTypeface;
+namespace cc {
+class PaintCanvas;
+}
+
namespace gfx {
namespace test {
class RenderTextTestApi;
@@ -81,8 +85,8 @@
private:
friend class test::RenderTextTestApi;
- Canvas* canvas_;
- cc::PaintCanvas* canvas_skia_;
+ raw_ptr<Canvas> canvas_;
+ raw_ptr<cc::PaintCanvas> canvas_skia_;
cc::PaintFlags flags_;
SkFont font_;
};
@@ -127,11 +131,11 @@
private:
// Pointers to the breaklists to iterate through. These pointers can't be
// nullptr and the breaklists must outlive this object.
- const BreakList<SkColor>* colors_;
- const BreakList<BaselineStyle>* baselines_;
- const BreakList<int>* font_size_overrides_;
- const BreakList<Font::Weight>* weights_;
- const StyleArray* styles_;
+ raw_ptr<const BreakList<SkColor>> colors_;
+ raw_ptr<const BreakList<BaselineStyle>> baselines_;
+ raw_ptr<const BreakList<int>> font_size_overrides_;
+ raw_ptr<const BreakList<Font::Weight>> weights_;
+ raw_ptr<const StyleArray> styles_;
BreakList<SkColor>::const_iterator color_;
BreakList<BaselineStyle>::const_iterator baseline_;
@@ -211,7 +215,7 @@
// for rendering and translation between logical and visual data.
class GFX_EXPORT RenderText {
public:
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// On Mac, while selecting text if the cursor is outside the vertical text
// bounds, drag to the end of the text.
static constexpr bool kDragToEndIfOutsideVerticalBounds = true;
@@ -293,10 +297,10 @@
// Makes a char in obscured text at |index| to be revealed. |index| should be
// a UTF16 text index. If there is a previous revealed index, the previous one
- // is cleared and only the last set index will be revealed. If |index| is -1
- // or out of range, no char will be revealed. The revealed index is also
- // cleared when SetText or SetObscured is called.
- void SetObscuredRevealIndex(int index);
+ // is cleared and only the last set index will be revealed. If |index| is
+ // nullopt or out of range, no char will be revealed. The revealed index is
+ // also cleared when SetText or SetObscured is called.
+ void SetObscuredRevealIndex(absl::optional<size_t> index);
// For obscured (password) fields, the extra spacing between glyphs.
int obscured_glyph_spacing() const { return obscured_glyph_spacing_; }
@@ -617,6 +621,10 @@
// resulting range. Maintains directionality of |range|.
Range ExpandRangeToGraphemeBoundary(const Range& range) const;
+ // Expands |range| to its nearest word boundaries and returns the resulting
+ // range. Maintains directionality of |range|.
+ Range ExpandRangeToWordBoundary(const Range& range) const;
+
// Specify the width/height of a glyph for test. The width/height of glyphs is
// very platform-dependent and environment-dependent. Otherwise multiline text
// will become really flaky.
@@ -764,9 +772,6 @@
// Update the display text.
void UpdateDisplayText(float text_width);
- // Returns display text positions that are suitable for breaking lines.
- const BreakList<size_t>& GetLineBreaks();
-
// Convert points from the text space to the view space. Handles the display
// area, display offset, application LTR/RTL mode and multiline. |line| is the
// index of the line in which |point| is found, and is required to be passed
@@ -873,10 +878,6 @@
// the text length if no valid boundary is found.
size_t GetNearestWordStartBoundary(size_t index) const;
- // Expands |range| to its nearest word boundaries and returns the resulting
- // range. Maintains directionality of |range|.
- Range ExpandRangeToWordBoundary(const Range& range) const;
-
// Returns an implementation-specific run list, if implemented.
virtual internal::TextRunList* GetRunList() = 0;
virtual const internal::TextRunList* GetRunList() const = 0;
@@ -967,7 +968,7 @@
// A flag to obscure actual text with asterisks for password fields.
bool obscured_ = false;
// The index at which the char should be revealed in the obscured text.
- int obscured_reveal_index_ = -1;
+ absl::optional<size_t> obscured_reveal_index_;
// The maximum length of text to display, 0 forgoes a hard limit.
size_t truncate_length_ = 0;
@@ -1034,9 +1035,6 @@
// Text shadows to be drawn.
ShadowValues shadows_;
- // A list of valid display text line break positions.
- BreakList<size_t> line_breaks_;
-
// Text shaping computed by EnsureLayout. This should be invalidated upon
// OnLayoutTextAttributeChanged and OnDisplayTextAttributeChanged calls.
std::unique_ptr<internal::ShapedText> shaped_text_;
diff --git a/ui/gfx/render_text_api_fuzzer.cc b/ui/gfx/render_text_api_fuzzer.cc
index 8d39dfc..3d9f75a 100644
--- a/ui/gfx/render_text_api_fuzzer.cc
+++ b/ui/gfx/render_text_api_fuzzer.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -12,23 +12,23 @@
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/task_environment.h"
+#include "base/test/test_discardable_memory_allocator.h"
#include "base/test/test_timeouts.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/font_util.h"
#include "ui/gfx/render_text.h"
-// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
-// complete.
-#if defined(OS_ANDROID) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
-#include "base/test/test_discardable_memory_allocator.h"
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#include "third_party/test_fonts/fontconfig/fontconfig_util_linux.h"
#endif
namespace {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const char kFontDescription[] = "Segoe UI, 13px";
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
const char kFontDescription[] = "serif, 13px";
#else
const char kFontDescription[] = "sans, 13px";
@@ -40,23 +40,21 @@
TestTimeouts::Initialize(),
base::test::TaskEnvironment::MainThreadType::UI)) {
logging::SetMinLogLevel(logging::LOG_FATAL);
-// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
-// complete.
-#if defined(OS_ANDROID) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
+
// Some platforms require discardable memory to use bitmap fonts.
base::DiscardableMemoryAllocator::SetInstance(
&discardable_memory_allocator);
-#endif
+
CHECK(base::i18n::InitializeICU());
+
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+ test_fonts::SetUpFontconfig();
+#endif
+ gfx::InitializeFonts();
gfx::FontList::SetDefaultFontDescription(kFontDescription);
}
-// TODO(crbug.com/1052397): Revisit once build flag switch of lacros-chrome is
-// complete.
-#if defined(OS_ANDROID) || (defined(OS_LINUX) || BUILDFLAG(IS_CHROMEOS_LACROS))
base::TestDiscardableMemoryAllocator discardable_memory_allocator;
-#endif
-
base::AtExitManager at_exit_manager;
base::test::TaskEnvironment task_environment;
};
@@ -161,24 +159,44 @@
}
}
-gfx::ElideBehavior ConsumeElideBehavior(FuzzedDataProvider* fdp) {
- switch (fdp->ConsumeIntegralInRange(0, 7)) {
- case 0:
- return gfx::NO_ELIDE;
- case 1:
- return gfx::TRUNCATE;
- case 2:
- return gfx::ELIDE_HEAD;
- case 3:
- return gfx::ELIDE_MIDDLE;
- case 4:
- return gfx::ELIDE_TAIL;
- case 5:
- return gfx::ELIDE_EMAIL;
- case 6:
- return gfx::FADE_TAIL;
- default:
- return gfx::NO_ELIDE;
+gfx::ElideBehavior ConsumeElideBehavior(FuzzedDataProvider* fdp,
+ bool generate_only_homogeneous_styles) {
+ if (generate_only_homogeneous_styles) {
+ // The styles are guaranteed to be homogenous and it is safe to generate
+ // any eliding behavior.
+ switch (fdp->ConsumeIntegralInRange(0, 7)) {
+ case 0:
+ return gfx::NO_ELIDE;
+ case 1:
+ return gfx::TRUNCATE;
+ case 2:
+ return gfx::ELIDE_HEAD;
+ case 3:
+ return gfx::ELIDE_MIDDLE;
+ case 4:
+ return gfx::ELIDE_TAIL;
+ case 5:
+ return gfx::ELIDE_EMAIL;
+ case 6:
+ return gfx::FADE_TAIL;
+ default:
+ return gfx::NO_ELIDE;
+ }
+ } else {
+ // Only generate eliding behaviors that are compatible with non homogeneous
+ // text. Remove this when http://crbug.com/1085014 is fixed.
+ switch (fdp->ConsumeIntegralInRange(0, 4)) {
+ case 0:
+ return gfx::NO_ELIDE;
+ case 1:
+ return gfx::TRUNCATE;
+ case 2:
+ return gfx::ELIDE_TAIL;
+ case 3:
+ return gfx::FADE_TAIL;
+ default:
+ return gfx::NO_ELIDE;
+ }
}
}
@@ -208,6 +226,16 @@
return gfx::Range(start, end);
}
+// Eliding behaviors are not all fully supported by RenderText. Ignore
+// unsupported cases. This is causing clusterfuzz to fail with invalid
+// tests (http://crbug.com/1185542). Remove when https://crbug.com/1085014 is
+// fixed.
+bool DoesDisplayRangeSupportElideBehavior(const gfx::RenderText* render_text) {
+ const gfx::ElideBehavior behavior = render_text->elide_behavior();
+ return behavior != gfx::ELIDE_HEAD && behavior != gfx::ELIDE_MIDDLE &&
+ behavior != gfx::ELIDE_EMAIL;
+}
+
const int kMaxStringLength = 128;
} // anonymous namespace
@@ -220,6 +248,14 @@
gfx::Canvas canvas;
FuzzedDataProvider fdp(data, size);
+ if (size == 0)
+ return 0;
+
+ // Eliding and Styles are not well supported by RenderText. DCHECKs are
+ // present in RenderText code to avoid any incorrect uses but the fuzzer
+ // should not generate them until full support (http://crbug.com/1283159).
+ const bool generate_only_homogeneous_styles = fdp.ConsumeBool();
+
while (fdp.remaining_bytes() != 0) {
const RenderTextAPI command = fdp.ConsumeEnum<RenderTextAPI>();
switch (command) {
@@ -280,7 +316,9 @@
break;
case RenderTextAPI::kSetMultiline:
- render_text->SetMultiline(fdp.ConsumeBool());
+ if (generate_only_homogeneous_styles) {
+ render_text->SetMultiline(fdp.ConsumeBool());
+ }
break;
case RenderTextAPI::kSetMaxLines:
@@ -304,9 +342,11 @@
break;
case RenderTextAPI::kApplyColor:
- render_text->ApplyColor(
- ConsumeSkColor(&fdp),
- ConsumeRange(&fdp, render_text->text().length()));
+ if (!generate_only_homogeneous_styles) {
+ render_text->ApplyColor(
+ ConsumeSkColor(&fdp),
+ ConsumeRange(&fdp, render_text->text().length()));
+ }
break;
case RenderTextAPI::kSetStyle:
@@ -314,9 +354,11 @@
break;
case RenderTextAPI::kApplyStyle:
- render_text->ApplyStyle(
- ConsumeStyle(&fdp), fdp.ConsumeBool(),
- ConsumeRange(&fdp, render_text->text().length()));
+ if (!generate_only_homogeneous_styles) {
+ render_text->ApplyStyle(
+ ConsumeStyle(&fdp), fdp.ConsumeBool(),
+ ConsumeRange(&fdp, render_text->text().length()));
+ }
break;
case RenderTextAPI::kSetWeight:
@@ -324,9 +366,11 @@
break;
case RenderTextAPI::kApplyWeight:
- render_text->ApplyWeight(
- ConsumeWeight(&fdp),
- ConsumeRange(&fdp, render_text->text().length()));
+ if (!generate_only_homogeneous_styles) {
+ render_text->ApplyWeight(
+ ConsumeWeight(&fdp),
+ ConsumeRange(&fdp, render_text->text().length()));
+ }
break;
case RenderTextAPI::kSetDirectionalityMode:
@@ -334,7 +378,8 @@
break;
case RenderTextAPI::kSetElideBehavior:
- render_text->SetElideBehavior(ConsumeElideBehavior(&fdp));
+ render_text->SetElideBehavior(
+ ConsumeElideBehavior(&fdp, generate_only_homogeneous_styles));
break;
case RenderTextAPI::kIsGraphemeBoundary:
@@ -362,10 +407,18 @@
fdp.ConsumeIntegralInRange<int>(0, 30)));
break;
case RenderTextAPI::kGetSubstringBounds:
+ // RenderText doesn't support that case (https://crbug.com/1085014).
+ if (!DoesDisplayRangeSupportElideBehavior(render_text.get()))
+ break;
+
render_text->GetSubstringBounds(
ConsumeRange(&fdp, render_text->text().length()));
break;
case RenderTextAPI::kGetCursorSpan:
+ // RenderText doesn't support that case (https://crbug.com/1085014).
+ if (!DoesDisplayRangeSupportElideBehavior(render_text.get()))
+ break;
+
render_text->GetCursorSpan(
ConsumeRange(&fdp, render_text->text().length()));
break;
diff --git a/ui/gfx/render_text_fuzzer.cc b/ui/gfx/render_text_fuzzer.cc
index 9ce8bc6..88468fe 100644
--- a/ui/gfx/render_text_fuzzer.cc
+++ b/ui/gfx/render_text_fuzzer.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -11,13 +11,18 @@
#include "base/test/test_timeouts.h"
#include "build/build_config.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/font_util.h"
#include "ui/gfx/render_text.h"
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+#include "third_party/test_fonts/fontconfig/fontconfig_util_linux.h"
+#endif
+
namespace {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const char kFontDescription[] = "Segoe UI, 13px";
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
const char kFontDescription[] = "serif, 13px";
#else
const char kFontDescription[] = "sans, 13px";
@@ -31,6 +36,11 @@
logging::SetMinLogLevel(logging::LOG_FATAL);
CHECK(base::i18n::InitializeICU());
+
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+ test_fonts::SetUpFontconfig();
+#endif
+ gfx::InitializeFonts();
gfx::FontList::SetDefaultFontDescription(kFontDescription);
}
diff --git a/ui/gfx/render_text_harfbuzz.cc b/ui/gfx/render_text_harfbuzz.cc
index 9e99256..a74fd23 100644
--- a/ui/gfx/render_text_harfbuzz.cc
+++ b/ui/gfx/render_text_harfbuzz.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,8 +9,11 @@
#include "base/command_line.h"
#include "base/containers/contains.h"
-#include "base/containers/mru_cache.h"
+#include "base/containers/lru_cache.h"
#include "base/containers/span.h"
+#include "base/debug/alias.h"
+#include "base/debug/crash_logging.h"
+#include "base/debug/dump_without_crashing.h"
#include "base/feature_list.h"
#include "base/hash/hash.h"
#include "base/i18n/base_i18n_switches.h"
@@ -18,12 +21,14 @@
#include "base/i18n/char_iterator.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/memory/ptr_util.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ref.h"
#include "base/metrics/histogram_macros.h"
#include "base/no_destructor.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task/current_thread.h"
@@ -49,15 +54,15 @@
#include "ui/gfx/text_utils.h"
#include "ui/gfx/utf16_indexing.h"
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "base/mac/foundation_util.h"
#include "base/mac/mac_util.h"
#include "third_party/skia/include/ports/SkTypeface_mac.h"
#endif
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
#include "base/android/locale_utils.h"
-#endif // defined(OS_ANDROID)
+#endif // BUILDFLAG(IS_ANDROID)
#include <hb.h>
@@ -412,7 +417,6 @@
float glyph_height_for_test,
WordWrapBehavior word_wrap_behavior,
const std::u16string& text,
- const BreakList<size_t>* words,
const internal::TextRunList& run_list)
: max_width_((max_width == 0) ? SK_ScalarMax : SkIntToScalar(max_width)),
min_baseline_(min_baseline),
@@ -420,7 +424,6 @@
glyph_height_for_test_(glyph_height_for_test),
word_wrap_behavior_(word_wrap_behavior),
text_(text),
- words_(words),
run_list_(run_list),
max_descent_(0),
max_ascent_(0),
@@ -434,8 +437,8 @@
// Constructs a single line for |text_| using |run_list_|.
void ConstructSingleLine() {
- for (size_t i = 0; i < run_list_.size(); i++) {
- const internal::TextRunHarfBuzz& run = *(run_list_.runs()[i]);
+ for (size_t i = 0; i < run_list_->size(); i++) {
+ const internal::TextRunHarfBuzz& run = *(run_list_->runs()[i]);
internal::LineSegment segment;
segment.run = i;
segment.char_range = run.range;
@@ -447,10 +450,17 @@
// Constructs multiple lines for |text_| based on words iteration approach.
void ConstructMultiLines() {
- DCHECK(words_);
- for (auto iter = words_->breaks().begin(); iter != words_->breaks().end();
- iter++) {
- const Range word_range = words_->GetRange(iter);
+ // Get an iterator that pass through valid line breaking positions.
+ // See https://www.unicode.org/reports/tr14/tr14-11.html for lines breaking.
+ base::i18n::BreakIterator words(*text_,
+ base::i18n::BreakIterator::BREAK_LINE);
+ const bool success = words.Init();
+ DCHECK(success);
+ if (!success)
+ return;
+
+ while (words.Advance()) {
+ const Range word_range = Range(words.prev(), words.pos());
std::vector<internal::LineSegment> word_segments;
SkScalar word_width = GetWordWidth(word_range, &word_segments);
@@ -458,7 +468,7 @@
// the word to the current line.
bool new_line = false;
if (!word_segments.empty() &&
- IsNewlineSegment(text_, word_segments.back())) {
+ IsNewlineSegment(*text_, word_segments.back())) {
new_line = true;
// Subtract the width of newline segments, they are not drawn.
@@ -487,7 +497,7 @@
// the final line.
internal::Line* line = &lines_.back();
if (line->display_text_index == 0)
- line->display_text_index = text_.size();
+ line->display_text_index = text_->size();
// Add an empty line to finish the line size calculation and remove it.
AdvanceLine();
lines_.pop_back();
@@ -516,8 +526,8 @@
std::sort(line->segments.begin(), line->segments.end(),
[this](const internal::LineSegment& s1,
const internal::LineSegment& s2) -> bool {
- return run_list_.logical_to_visual(s1.run) <
- run_list_.logical_to_visual(s2.run);
+ return run_list_->logical_to_visual(s1.run) <
+ run_list_->logical_to_visual(s2.run);
});
line->size.set_height(
@@ -531,11 +541,11 @@
// drawn.
float line_width = line->size.width();
if (!line->segments.empty() &&
- IsNewlineSegment(text_, line->segments.back())) {
+ IsNewlineSegment(*text_, line->segments.back())) {
line_width -= line->segments.back().width();
}
if (line->segments.size() > 1 &&
- IsNewlineSegment(text_, line->segments.front())) {
+ IsNewlineSegment(*text_, line->segments.front())) {
line_width -= line->segments.front().width();
}
total_size_.set_height(total_size_.height() + line->size.height());
@@ -559,7 +569,7 @@
if (has_truncated)
break;
- if (IsNewlineSegment(text_, segment) ||
+ if (IsNewlineSegment(*text_, segment) ||
segment.width() <= available_width_ ||
word_wrap_behavior_ == IGNORE_LONG_WORDS) {
AddLineSegment(segment, true);
@@ -568,13 +578,14 @@
word_wrap_behavior_ == WRAP_LONG_WORDS);
has_truncated = (word_wrap_behavior_ == TRUNCATE_LONG_WORDS);
- const internal::TextRunHarfBuzz& run = *(run_list_.runs()[segment.run]);
+ const internal::TextRunHarfBuzz& run =
+ *(run_list_->runs()[segment.run]);
internal::LineSegment remaining_segment = segment;
while (!remaining_segment.char_range.is_empty()) {
size_t cutoff_pos = GetCutoffPos(remaining_segment);
SkScalar width = run.GetGlyphWidthForCharRange(
Range(remaining_segment.char_range.start(), cutoff_pos));
- if (width > 0) {
+ if (remaining_segment.char_range.start() != cutoff_pos) {
internal::LineSegment cut_segment;
cut_segment.run = remaining_segment.run;
cut_segment.char_range =
@@ -601,7 +612,7 @@
void AddLineSegment(const internal::LineSegment& segment, bool multiline) {
DCHECK(!lines_.empty());
internal::Line* line = &lines_.back();
- const internal::TextRunHarfBuzz& run = *(run_list_.runs()[segment.run]);
+ const internal::TextRunHarfBuzz& run = *(run_list_->runs()[segment.run]);
if (!line->segments.empty()) {
internal::LineSegment& last_segment = line->segments.back();
// Merge segments that belong to the same run.
@@ -627,7 +638,7 @@
line->size.set_width(line->size.width() + segment.width());
// Newline characters are not drawn for multi-line, ignore their metrics.
- if (!multiline || !IsNewlineSegment(text_, segment)) {
+ if (!multiline || !IsNewlineSegment(*text_, segment)) {
SkFont font(run.font_params.skia_face, run.font_params.font_size);
font.setEdging(run.font_params.render_params.antialiasing
? SkFont::Edging::kAntiAlias
@@ -660,7 +671,7 @@
size_t GetCutoffPos(const internal::LineSegment& segment) const {
DCHECK(!segment.char_range.is_empty());
const internal::TextRunHarfBuzz& run =
- *(run_list_.runs()[segment.run]).get();
+ *(run_list_->runs()[segment.run]).get();
size_t end_pos = segment.char_range.start();
SkScalar width = 0;
while (end_pos < segment.char_range.end()) {
@@ -673,8 +684,7 @@
}
const size_t valid_end_pos = std::max(
- segment.char_range.start(),
- static_cast<uint32_t>(FindValidBoundaryBefore(text_, end_pos)));
+ segment.char_range.start(), FindValidBoundaryBefore(*text_, end_pos));
if (end_pos != valid_end_pos) {
end_pos = valid_end_pos;
width = run.GetGlyphWidthForCharRange(
@@ -685,10 +695,10 @@
// need to put at least one character in the line. Note that, we should
// not separate surrogate pair or combining characters.
// See RenderTextHarfBuzzTest.Multiline_MinWidth for an example.
- if (width == 0 && available_width_ == max_width_) {
- end_pos = std::min(
- segment.char_range.end(),
- static_cast<uint32_t>(FindValidBoundaryAfter(text_, end_pos + 1)));
+ if (width == 0 && available_width_ == max_width_ &&
+ end_pos < segment.char_range.end()) {
+ end_pos = std::min(segment.char_range.end(),
+ FindValidBoundaryAfter(*text_, end_pos + 1));
}
return end_pos;
@@ -698,14 +708,13 @@
// segments based on its runs.
SkScalar GetWordWidth(const Range& word_range,
std::vector<internal::LineSegment>* segments) const {
- DCHECK(words_);
if (word_range.is_empty() || segments == nullptr)
return 0;
- size_t run_start_index = run_list_.GetRunIndexAt(word_range.start());
- size_t run_end_index = run_list_.GetRunIndexAt(word_range.end() - 1);
+ size_t run_start_index = run_list_->GetRunIndexAt(word_range.start());
+ size_t run_end_index = run_list_->GetRunIndexAt(word_range.end() - 1);
SkScalar width = 0;
for (size_t i = run_start_index; i <= run_end_index; i++) {
- const internal::TextRunHarfBuzz& run = *(run_list_.runs()[i]);
+ const internal::TextRunHarfBuzz& run = *(run_list_->runs()[i]);
const Range char_range = run.range.Intersect(word_range);
DCHECK(!char_range.is_empty());
const SkScalar char_width = run.GetGlyphWidthForCharRange(char_range);
@@ -743,9 +752,8 @@
const float min_height_;
const float glyph_height_for_test_;
const WordWrapBehavior word_wrap_behavior_;
- const std::u16string& text_;
- const BreakList<size_t>* const words_;
- const internal::TextRunList& run_list_;
+ const raw_ref<const std::u16string> text_;
+ const raw_ref<const internal::TextRunList> run_list_;
// Stores the resulting lines.
std::vector<internal::Line> lines_;
@@ -805,6 +813,42 @@
return font_params;
}
+BASE_FEATURE(kRemoveFontLinkFallbacks,
+ "RemoveFontLinkFallbacks",
+ base::FEATURE_DISABLED_BY_DEFAULT);
+
+bool IsRemoveFontLinkFallbacks() {
+ return base::FeatureList::IsEnabled(kRemoveFontLinkFallbacks);
+}
+
+BASE_FEATURE(kEnableFallbackFontsCrashReporting,
+ "EnableFallbackFontsCrashReporting",
+ base::FEATURE_DISABLED_BY_DEFAULT);
+
+bool IsEnableFallbackFontsCrashReporting() {
+ return base::FeatureList::IsEnabled(kEnableFallbackFontsCrashReporting);
+}
+
+// Append to `in_out_report` the font name and the text correlating to the runs
+// shaped by that font. This crash report will be used to debug why text is
+// being shaped through the GetFallbackFonts path as we shouldn't need to
+// fallback to that call path. crbug.com/995789
+void AppendFontNameAndShapedTextToCrashDumpReport(
+ const std::u16string& text,
+ const std::vector<internal::TextRunHarfBuzz*>& shaped_runs,
+ const std::string& font_name,
+ std::u16string& report) {
+ const std::u16string font_name_seperator = u"[font name] ";
+ const std::u16string run_start = u"[run start] ";
+ const std::u16string run_end = u" [run end]";
+ report += font_name_seperator + base::ASCIIToUTF16(font_name.c_str());
+ for (internal::TextRunHarfBuzz* run : shaped_runs) {
+ std::u16string text_substring =
+ text.substr(run->range.start(), run->range.end());
+ report += run_start + text_substring + run_end;
+ }
+}
+
} // namespace
namespace internal {
@@ -812,14 +856,14 @@
sk_sp<SkTypeface> CreateSkiaTypeface(const Font& font,
bool italic,
Font::Weight weight) {
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
const Font::FontStyle style = italic ? Font::ITALIC : Font::NORMAL;
Font font_with_style = font.Derive(0, style, weight);
- if (!font_with_style.GetNativeFont())
+ if (!font_with_style.GetCTFont()) {
return nullptr;
+ }
- return SkMakeTypefaceFromCTFont(
- base::mac::NSToCFCast(font_with_style.GetNativeFont()));
+ return SkMakeTypefaceFromCTFont(font_with_style.GetCTFont());
#else
SkFontStyle skia_style(
static_cast<int>(weight), SkFontStyle::kNormal_Width,
@@ -1020,10 +1064,18 @@
Range chars;
Range glyphs;
GetClusterAt(text_index, &chars, &glyphs);
- const float cluster_begin_x = shape.positions[glyphs.start()].x();
- const float cluster_end_x = glyphs.end() < shape.glyph_count
- ? shape.positions[glyphs.end()].x()
- : SkFloatToScalar(shape.width);
+ // Obscured glyphs are centered in their allotted space by adjusting their
+ // positions during shaping. Include the space preceding the glyph when
+ // calculating grapheme bounds.
+ const float half_obscured_spacing =
+ render_text->obscured() ? render_text->obscured_glyph_spacing() / 2.0f
+ : 0.0f;
+ const float cluster_begin_x =
+ shape.positions[glyphs.start()].x() - half_obscured_spacing;
+ const float cluster_end_x =
+ glyphs.end() < shape.glyph_count
+ ? shape.positions[glyphs.end()].x() - half_obscured_spacing
+ : SkFloatToScalar(shape.width);
DCHECK_LE(cluster_begin_x, cluster_end_x);
// A cluster consists of a number of code points and corresponds to a number
@@ -1261,11 +1313,11 @@
size_t hash = 0;
};
-// An MRU cache of the results from calling ShapeRunWithFont. The maximum cache
+// An LRU cache of the results from calling ShapeRunWithFont. The maximum cache
// size used in blink::ShapeCache is 10k. A Finch experiment showed that
// reducing the cache size to 1k has no performance impact.
constexpr int kShapeRunCacheSize = 1000;
-using ShapeRunCacheBase = base::HashingMRUCache<ShapeRunWithFontInput,
+using ShapeRunCacheBase = base::HashingLRUCache<ShapeRunWithFontInput,
TextRunHarfBuzz::ShapeOutput,
ShapeRunWithFontInput::Hash>;
class ShapeRunCache : public ShapeRunCacheBase {
@@ -1328,9 +1380,14 @@
out->missing_glyph_count += 1;
DCHECK_GE(infos[i].cluster, in.range.start());
out->glyph_to_char[i] = infos[i].cluster - in.range.start();
- const SkScalar x_offset =
- force_zero_offset ? 0
- : HarfBuzzUnitsToSkiaScalar(hb_positions[i].x_offset);
+
+ SkScalar x_offset = HarfBuzzUnitsToSkiaScalar(hb_positions[i].x_offset);
+
+ if (in.obscured)
+ // Place obscured glyphs in the middle of the allotted spacing.
+ x_offset += in.obscured_glyph_spacing / 2.0f;
+ if (force_zero_offset)
+ x_offset = 0;
const SkScalar y_offset =
HarfBuzzUnitsToSkiaScalar(hb_positions[i].y_offset);
out->positions[i].set(out->width + x_offset, -y_offset);
@@ -1359,7 +1416,7 @@
}
std::string GetApplicationLocale() {
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// TODO(etienneb): Android locale should work the same way than base locale.
return base::android::GetDefaultLocaleString();
#else
@@ -1603,7 +1660,7 @@
if (run == run_list->size())
break;
size_t cursor = current.caret_pos();
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Windows generally advances to the start of a word in either direction.
// TODO: Break on the end of a word when the neighboring text is
// punctuation.
@@ -1614,7 +1671,7 @@
run_list->runs()[run]->font_params.is_rtl == (direction == CURSOR_LEFT);
if (is_forward ? iter.IsEndOfWord(cursor) : iter.IsStartOfWord(cursor))
break;
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
}
return current;
}
@@ -1691,7 +1748,7 @@
display_rect().width(),
DetermineBaselineCenteringText(height, font_list()), height,
glyph_height_for_test_, word_wrap_behavior(), GetDisplayText(),
- multiline() ? &GetLineBreaks() : nullptr, *run_list);
+ *run_list);
if (multiline())
line_breaker.ConstructMultiLines();
@@ -1699,7 +1756,9 @@
line_breaker.ConstructSingleLine();
std::vector<internal::Line> lines;
line_breaker.FinalizeLines(&lines, &total_size_);
- if (multiline() && max_lines()) {
+ // In multiline, only ELIDE_TAIL is supported. max_lines_ is not used
+ // otherwise.
+ if (multiline() && max_lines() && elide_behavior() == ELIDE_TAIL) {
// TODO(crbug.com/866720): no more than max_lines() should be rendered.
// Remove the IsHomogeneous() condition for the following DCHECK when the
// bug is fixed.
@@ -1753,7 +1812,7 @@
renderer->SetTextSize(SkIntToScalar(run.font_params.font_size));
renderer->SetFontRenderParams(run.font_params.render_params,
subpixel_rendering_suppressed());
- Range glyphs_range = run.CharRangeToGlyphRange(segment.char_range);
+ const Range glyphs_range = run.CharRangeToGlyphRange(segment.char_range);
std::vector<SkPoint> positions(glyphs_range.length());
SkScalar offset_x = preceding_segment_widths -
((glyphs_range.GetMin() != 0)
@@ -1780,6 +1839,16 @@
if (colored_glyphs.is_empty())
continue;
+ const size_t colored_pos =
+ colored_glyphs.start() - glyphs_range.start();
+ const int pos_size = positions.size();
+ base::debug::Alias(&colored_pos);
+ base::debug::Alias(&pos_size);
+ const size_t crash_report_size = 256;
+ DEBUG_ALIAS_FOR_U16CSTR(alias_display_text, display_text.c_str(),
+ crash_report_size);
+ DEBUG_ALIAS_FOR_U16CSTR(alias_text, text().c_str(), crash_report_size);
+
renderer->SetForegroundColor(it->second);
renderer->DrawPosText(
&positions[colored_glyphs.start() - glyphs_range.start()],
@@ -2053,38 +2122,44 @@
return;
}
- std::vector<Font> fallback_font_list;
- {
- SCOPED_UMA_HISTOGRAM_LONG_TIMER("RenderTextHarfBuzz.GetFallbackFontsTime");
- TRACE_EVENT1("ui", "RenderTextHarfBuzz::GetFallbackFonts", "script",
- TRACE_STR_COPY(uscript_getShortName(font_params.script)));
- fallback_font_list = GetFallbackFonts(primary_font);
+ if (!IsRemoveFontLinkFallbacks()) {
+ // Used for crash reporting below.
+ static bool is_first_crash = true;
-#if defined(OS_WIN)
- // Append fonts in the fallback list of the fallback fonts.
- // TODO(tapted): Investigate whether there's a case that benefits from this
- // on Mac.
- for (const auto& fallback_font : fallback_font_candidates) {
- std::vector<Font> fallback_fonts = GetFallbackFonts(fallback_font);
- fallback_font_list.insert(fallback_font_list.end(),
- fallback_fonts.begin(), fallback_fonts.end());
- }
+ std::vector<Font> fallback_font_list;
+ std::u16string crash_report_string;
+ {
+ SCOPED_UMA_HISTOGRAM_LONG_TIMER(
+ "RenderTextHarfBuzz.GetFallbackFontsTime");
+ TRACE_EVENT1("ui", "RenderTextHarfBuzz::GetFallbackFonts", "script",
+ TRACE_STR_COPY(uscript_getShortName(font_params.script)));
+ fallback_font_list = GetFallbackFonts(primary_font);
- // Add Segoe UI and its associated linked fonts to the fallback font list to
- // ensure that the fallback list covers the basic cases.
- // http://crbug.com/467459. On some Windows configurations the default font
- // could be a raster font like System, which would not give us a reasonable
- // fallback font list.
- Font segoe("Segoe UI", 13);
- if (!FontWasAlreadyTried(segoe.platform_font()->GetNativeSkTypeface(),
- &fallback_fonts_already_tried)) {
- std::vector<Font> default_fallback_families = GetFallbackFonts(segoe);
- fallback_font_list.insert(fallback_font_list.end(),
- default_fallback_families.begin(),
- default_fallback_families.end());
- }
+#if BUILDFLAG(IS_WIN)
+ // Append fonts in the fallback list of the fallback fonts.
+ // TODO(tapted): Investigate whether there's a case that benefits from
+ // this on Mac.
+ for (const auto& fallback_font : fallback_font_candidates) {
+ std::vector<Font> fallback_fonts = GetFallbackFonts(fallback_font);
+ fallback_font_list.insert(fallback_font_list.end(),
+ fallback_fonts.begin(), fallback_fonts.end());
+ }
+
+ // Add Segoe UI and its associated linked fonts to the fallback font list
+ // to ensure that the fallback list covers the basic cases.
+ // http://crbug.com/467459. On some Windows configurations the default
+ // font could be a raster font like System, which would not give us a
+ // reasonable fallback font list.
+ Font segoe("Segoe UI", 13);
+ if (!FontWasAlreadyTried(segoe.platform_font()->GetNativeSkTypeface(),
+ &fallback_fonts_already_tried)) {
+ std::vector<Font> default_fallback_families = GetFallbackFonts(segoe);
+ fallback_font_list.insert(fallback_font_list.end(),
+ default_fallback_families.begin(),
+ default_fallback_families.end());
+ }
#endif
- }
+ }
// Use a set to track the fallback fonts and avoid duplicate entries.
SCOPED_UMA_HISTOGRAM_LONG_TIMER(
@@ -2094,30 +2169,56 @@
// Try shaping with the fallback fonts.
for (const auto& font : fallback_font_list) {
- std::string font_name = font.GetFontName();
+ std::string font_name = font.GetFontName();
- FontRenderParamsQuery query;
- query.families.push_back(font_name);
- query.pixel_size = font_params.font_size;
- query.style = font_params.italic ? Font::ITALIC : 0;
- FontRenderParams fallback_render_params = GetFontRenderParams(query, NULL);
- internal::TextRunHarfBuzz::FontParams test_font_params = font_params;
- if (test_font_params.SetRenderParamsOverrideSkiaFaceFromFont(
- font, fallback_render_params) &&
- !FontWasAlreadyTried(test_font_params.skia_face,
- &fallback_fonts_already_tried)) {
- ShapeRunsWithFont(text, test_font_params, &runs);
- MarkFontAsTried(test_font_params.skia_face,
- &fallback_fonts_already_tried);
- }
- if (runs.empty()) {
- TRACE_EVENT_INSTANT2("ui", "RenderTextHarfBuzz::FallbackFont",
- TRACE_EVENT_SCOPE_THREAD, "font_name",
- TRACE_STR_COPY(font_name.c_str()),
- "primary_font_name", primary_font.GetFontName());
- RecordShapeRunsFallback(ShapeRunFallback::FALLBACKS);
- return;
- }
+ FontRenderParamsQuery query;
+ query.families.push_back(font_name);
+ query.pixel_size = font_params.font_size;
+ query.style = font_params.italic ? Font::ITALIC : 0;
+ FontRenderParams fallback_render_params =
+ GetFontRenderParams(query, nullptr);
+ internal::TextRunHarfBuzz::FontParams test_font_params = font_params;
+ std::vector<internal::TextRunHarfBuzz*> fallback_fonts_shaped_runs;
+ if (test_font_params.SetRenderParamsOverrideSkiaFaceFromFont(
+ font, fallback_render_params) &&
+ !FontWasAlreadyTried(test_font_params.skia_face,
+ &fallback_fonts_already_tried)) {
+ ShapeRunsWithFont(text, test_font_params, &runs,
+ &fallback_fonts_shaped_runs);
+ MarkFontAsTried(test_font_params.skia_face,
+ &fallback_fonts_already_tried);
+ if (fallback_fonts_shaped_runs.size() > 0 && is_first_crash &&
+ IsEnableFallbackFontsCrashReporting()) {
+ AppendFontNameAndShapedTextToCrashDumpReport(
+ text, fallback_fonts_shaped_runs, font_name, crash_report_string);
+ }
+ }
+ if (runs.empty()) {
+ TRACE_EVENT_INSTANT2("ui", "RenderTextHarfBuzz::FallbackFont",
+ TRACE_EVENT_SCOPE_THREAD, "font_name",
+ TRACE_STR_COPY(font_name.c_str()),
+ "primary_font_name", primary_font.GetFontName());
+ RecordShapeRunsFallback(ShapeRunFallback::FALLBACKS);
+ // Resolving fallback fonts using the registry keys on windows will be
+ // deprecated and removed (see: http://crbug.com/995789). The crashes
+ // reported here should be fixed before deprecating the code.
+ if (is_first_crash && IsEnableFallbackFontsCrashReporting()) {
+ is_first_crash = false;
+ const size_t crash_report_size = 256;
+ DEBUG_ALIAS_FOR_U16CSTR(aliased_crash_report_string,
+ crash_report_string.c_str(),
+ crash_report_size);
+ DEBUG_ALIAS_FOR_U16CSTR(aliased_full_text, text.c_str(),
+ crash_report_size);
+ SCOPED_CRASH_KEY_STRING32("RenderTextFallbacks", "primaryfont_name",
+ primary_font.GetFontName());
+ SCOPED_CRASH_KEY_STRING32("RenderTextFallbacks", "primaryfont_script",
+ uscript_getShortName(font_params.script));
+ base::debug::DumpWithoutCrashing();
+ }
+ return;
+ }
+ }
}
for (internal::TextRunHarfBuzz*& run : runs) {
@@ -2133,11 +2234,12 @@
void RenderTextHarfBuzz::ShapeRunsWithFont(
const std::u16string& text,
const internal::TextRunHarfBuzz::FontParams& font_params,
- std::vector<internal::TextRunHarfBuzz*>* in_out_runs) {
- // ShapeRunWithFont can be extremely slow, so use cached results if possible.
- // Only do this on the UI thread, to avoid synchronization overhead (and
- // because almost all calls are on the UI thread. Also avoid caching long
- // strings, to avoid blowing up the cache size.
+ std::vector<internal::TextRunHarfBuzz*>* in_out_runs,
+ std::vector<internal::TextRunHarfBuzz*>* successfully_shaped_runs) {
+ // ShapeRunWithFont can be extremely slow, so use cached results if
+ // possible. Only do this on the UI thread, to avoid synchronization
+ // overhead (and because almost all calls are on the UI thread. Also avoid
+ // caching long strings, to avoid blowing up the cache size.
constexpr size_t kMaxRunLengthToCache = 25;
static base::NoDestructor<internal::ShapeRunCache> cache;
@@ -2170,8 +2272,11 @@
}
// Check to see if we still have missing glyphs.
- if (run->shape.missing_glyph_count)
+ if (run->shape.missing_glyph_count) {
runs_with_missing_glyphs.push_back(run);
+ } else if (successfully_shaped_runs) {
+ successfully_shaped_runs->push_back(run);
+ }
}
in_out_runs->swap(runs_with_missing_glyphs);
}
diff --git a/ui/gfx/render_text_harfbuzz.h b/ui/gfx/render_text_harfbuzz.h
index 64a823d..ba983b3 100644
--- a/ui/gfx/render_text_harfbuzz.h
+++ b/ui/gfx/render_text_harfbuzz.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -16,7 +16,6 @@
#include <utility>
#include <vector>
-#include "base/macros.h"
#include "third_party/icu/source/common/unicode/ubidi.h"
#include "third_party/icu/source/common/unicode/uscript.h"
#include "ui/gfx/render_text.h"
@@ -281,11 +280,15 @@
// resulting shaping has fewer missing glyphs than the existing shape, then
// write |font_params| and the resulting ShapeOutput to that run. Remove all
// runs with no missing glyphs from |in_out_runs| (the caller, ShapeRuns, will
- // terminate when no runs with missing glyphs remain).
+ // terminate when no runs with missing glyphs remain). Runs that were shaped
+ // during this function call will be returned in |sucessfully_shaped_runs| if
+ // a vector is passed in for that parameter.
void ShapeRunsWithFont(
const std::u16string& text,
const internal::TextRunHarfBuzz::FontParams& font_params,
- std::vector<internal::TextRunHarfBuzz*>* in_out_runs);
+ std::vector<internal::TextRunHarfBuzz*>* in_out_runs,
+ std::vector<internal::TextRunHarfBuzz*>* sucessfully_shaped_runs =
+ nullptr);
// Itemize |text| into runs in |out_run_list|, shape the runs, and populate
// |out_run_list|'s visual <-> logical maps.
diff --git a/ui/gfx/render_text_test_api.h b/ui/gfx/render_text_test_api.h
index e7a7b33..a3fff33 100644
--- a/ui/gfx/render_text_test_api.h
+++ b/ui/gfx/render_text_test_api.h
@@ -1,11 +1,11 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_RENDER_TEXT_TEST_API_H_
#define UI_GFX_RENDER_TEXT_TEST_API_H_
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
#include "ui/gfx/break_list.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/render_text.h"
@@ -120,7 +120,7 @@
}
private:
- RenderText* render_text_;
+ raw_ptr<RenderText> render_text_;
};
} // namespace test
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc
index 42f346c..b797278 100644
--- a/ui/gfx/render_text_unittest.cc
+++ b/ui/gfx/render_text_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,16 +8,20 @@
#include <stddef.h>
#include <stdint.h>
-#include <algorithm>
#include <memory>
#include <numeric>
+#include <set>
+#include <tuple>
-#include "base/cxx17_backports.h"
#include "base/format_macros.h"
#include "base/i18n/break_iterator.h"
#include "base/i18n/char_iterator.h"
#include "base/logging.h"
+#include "base/memory/raw_ptr.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/ranges/algorithm.h"
#include "base/run_loop.h"
+#include "base/strings/string_piece.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
@@ -33,6 +37,7 @@
#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/core/SkTextBlob.h"
#include "third_party/skia/include/core/SkTypeface.h"
+#include "ui/base/ui_base_features.h"
#include "ui/gfx/break_list.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/color_palette.h"
@@ -48,16 +53,15 @@
#include "ui/gfx/render_text_harfbuzz.h"
#include "ui/gfx/render_text_test_api.h"
#include "ui/gfx/switches.h"
+#include "ui/gfx/test/scoped_default_font_description.h"
#include "ui/gfx/text_elider.h"
#include "ui/gfx/text_utils.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
-
-#include "base/win/windows_version.h"
#endif
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
#include "base/mac/mac_util.h"
#endif
@@ -87,7 +91,7 @@
using FontSpan = std::pair<Font, Range>;
bool IsFontsSmoothingEnabled() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
BOOL antialiasing = TRUE;
BOOL result = SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &antialiasing, 0);
if (result == FALSE) {
@@ -185,10 +189,10 @@
int font_index,
Font::Weight weight,
int style_mask) {
- const auto iter = std::find_if(font_spans.cbegin(), font_spans.cend(),
- [font_index](const FontSpan& span) {
- return IndexInRange(span.second, font_index);
- });
+ const auto iter =
+ base::ranges::find_if(font_spans, [font_index](const FontSpan& span) {
+ return IndexInRange(span.second, font_index);
+ });
DCHECK(font_spans.end() != iter);
const Font& font = iter->first;
@@ -221,11 +225,9 @@
return IndexInRange(attr.range, i);
};
const auto expected_attr =
- std::find_if(expected.attributes.begin(), expected.attributes.end(),
- find_attribute_func);
+ base::ranges::find_if(expected.attributes, find_attribute_func);
const auto actual_attr =
- std::find_if(actual.attributes.begin(), actual.attributes.end(),
- find_attribute_func);
+ base::ranges::find_if(actual.attributes, find_attribute_func);
ASSERT_NE(expected.attributes.end(), expected_attr);
ASSERT_NE(actual.attributes.end(), actual_attr);
@@ -344,8 +346,8 @@
if (blob) {
SkTextBlob::Iter::Run run;
for (SkTextBlob::Iter it(*blob); it.next(&run);) {
- auto run_glyphs =
- base::span<const uint16_t>(run.fGlyphIndices, run.fGlyphCount);
+ auto run_glyphs = base::span<const uint16_t>(
+ run.fGlyphIndices, base::checked_cast<size_t>(run.fGlyphCount));
glyphs.insert(glyphs.end(), run_glyphs.begin(), run_glyphs.end());
}
}
@@ -413,7 +415,7 @@
private:
const char* string_;
- const SkColor* buffer_;
+ raw_ptr<const SkColor> buffer_;
int stride_;
int row_count_;
};
@@ -454,12 +456,12 @@
constexpr int kCanvasHeight = 400;
cc::PaintRecorder recorder;
- Canvas canvas(recorder.beginRecording(kCanvasWidth, kCanvasHeight), 1.0f);
+ Canvas canvas(recorder.beginRecording(), 1.0f);
test_api_->Draw(&canvas, select_all);
- sk_sp<cc::PaintRecord> record = recorder.finishRecordingAsPicture();
+ cc::PaintRecord record = recorder.finishRecordingAsPicture();
TestRenderTextCanvas test_canvas(kCanvasWidth, kCanvasHeight);
- record->Playback(&test_canvas);
+ record.Playback(&test_canvas);
test_canvas.GetTextLogAndReset(&text_log_);
}
@@ -476,11 +478,10 @@
std::vector<FontSpan> GetFontSpans() {
test_api()->EnsureLayout();
- const internal::TextRunList* run_list = GetHarfBuzzRunList();
std::vector<FontSpan> spans;
- std::transform(
- run_list->runs().begin(), run_list->runs().end(),
- std::back_inserter(spans), [this](const auto& run) {
+ base::ranges::transform(
+ GetHarfBuzzRunList()->runs(), std::back_inserter(spans),
+ [this](const auto& run) {
return FontSpan(
run->font_params.font,
Range(test_api()->DisplayIndexToTextIndex(run->range.start()),
@@ -509,12 +510,14 @@
size_t logical_index = run_list->visual_to_logical(i);
const internal::TextRunHarfBuzz& run = *run_list->runs()[logical_index];
if (run.range.length() == 1) {
- result.append(base::StringPrintf("[%d]", run.range.start()));
+ result.append(base::StringPrintf("[%" PRIuS "]", run.range.start()));
} else if (run.font_params.is_rtl) {
- result.append(base::StringPrintf("[%d<-%d]", run.range.end() - 1,
+ result.append(base::StringPrintf("[%" PRIuS "<-%" PRIuS "]",
+ run.range.end() - 1,
run.range.start()));
} else {
- result.append(base::StringPrintf("[%d->%d]", run.range.start(),
+ result.append(base::StringPrintf("[%" PRIuS "->%" PRIuS "]",
+ run.range.start(),
run.range.end() - 1));
}
}
@@ -540,8 +543,9 @@
}
void ResetRenderTextInstance() {
- render_text_ = std::make_unique<RenderTextHarfBuzz>();
- test_api_ = std::make_unique<test::RenderTextTestApi>(GetRenderText());
+ auto new_text = std::make_unique<RenderTextHarfBuzz>();
+ test_api_ = std::make_unique<test::RenderTextTestApi>(new_text.get());
+ render_text_ = std::move(new_text);
}
void ResetCursorX() { test_api()->reset_cached_cursor_x(); }
@@ -669,7 +673,7 @@
RenderText* render_text = GetRenderText();
EXPECT_TRUE(render_text->text().empty());
const char16_t* const cases[] = {kWeak, kLtr, u"Hello", kRtl, u"", u""};
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
EXPECT_TRUE(test_api()->colors().EqualsValueForTesting(kPlaceholderColor));
EXPECT_TRUE(test_api()->baselines().EqualsValueForTesting(NORMAL_BASELINE));
EXPECT_TRUE(test_api()->font_size_overrides().EqualsValueForTesting(0));
@@ -688,7 +692,7 @@
render_text->SetWeight(Font::Weight::BOLD);
render_text->SetStyle(TEXT_STYLE_UNDERLINE, false);
const char16_t* const cases[] = {kWeak, kLtr, u"Hello", kRtl, u"", u""};
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
EXPECT_TRUE(test_api()->colors().EqualsValueForTesting(color));
EXPECT_TRUE(test_api()->baselines().EqualsValueForTesting(SUPERSCRIPT));
EXPECT_TRUE(
@@ -1068,7 +1072,7 @@
SkImageInfo::MakeN32Premul(kCanvasSize.width(), kCanvasSize.height()));
cc::SkiaPaintCanvas paint_canvas(bitmap);
Canvas canvas(&paint_canvas, 1.0f);
- paint_canvas.clear(SK_ColorWHITE);
+ paint_canvas.clear(SkColors::kWhite);
SetGlyphWidth(kGlyphWidth);
RenderText* render_text = GetRenderText();
@@ -1261,7 +1265,7 @@
u"hop on pop", // Check LTR word boundaries.
u"אב אג בג", // Check RTL word boundaries.
};
- for (size_t i = 0; i < base::size(texts); ++i) {
+ for (size_t i = 0; i < std::size(texts); ++i) {
TestVisualCursorMotionInObscuredField(render_text, texts[i],
SELECTION_NONE);
TestVisualCursorMotionInObscuredField(render_text, texts[i],
@@ -1318,7 +1322,7 @@
render_text->GetDisplayText());
// Invalid reveal index.
- render_text->RenderText::SetObscuredRevealIndex(-1);
+ render_text->RenderText::SetObscuredRevealIndex(absl::nullopt);
EXPECT_EQ(no_seuss, render_text->GetDisplayText());
render_text->RenderText::SetObscuredRevealIndex(seuss.length() + 1);
EXPECT_EQ(no_seuss, render_text->GetDisplayText());
@@ -1567,9 +1571,9 @@
"[0][1][2][3][4]"}, // http://crbug.com/396776
{"jap_paren2", u"國哲(c)1",
"[0->1][2][3][4][5]"}, // http://crbug.com/125792
- {"newline1", u"\n\n", "[0->1]"},
- {"newline2", u"\r\n\r\n", "[0->3]"},
- {"newline3", u"\r\r\n", "[0->2]"},
+ {"newline1", u"\n\n", "[0][1]"},
+ {"newline2", u"\r\n\r\n", "[0][1][2][3]"},
+ {"newline3", u"\r\r\n", "[0->1][2]"},
{"multiline_newline1", u"\n\n", "[0][1]", true},
{"multiline_newline2", u"\r\n\r\n", "[0->1][2->3]", true},
{"multiline_newline3", u"\r\r\n", "[0][1->2]", true},
@@ -1751,7 +1755,7 @@
// Control Pictures.
{"control_pictures", u"␑␒␓␔␕␖␗␘␙␚␛", "[0->10]"},
- {"control_pictures_rewrite", u"␑\t␛", "[0->2]"},
+ {"control_pictures_rewrite", u"␑\t␛", "[0][1][2]"},
// Unicode art.
{"unicode_emoticon1", u"(▀̿ĺ̯▀̿ ̿)", "[0][1->2][3->4][5->6][7->8][9]"},
@@ -2643,7 +2647,7 @@
RenderText* render_text = GetRenderText();
render_text->set_truncate_length(5);
- for (size_t i = 0; i < base::size(cases); i++) {
+ for (size_t i = 0; i < std::size(cases); i++) {
render_text->SetText(cases[i].text);
EXPECT_EQ(cases[i].text, render_text->text());
EXPECT_EQ(cases[i].display_text, render_text->GetDisplayText())
@@ -2812,7 +2816,7 @@
SELECTION_NONE, &expected);
// Move right twice.
-#if defined(OS_WIN) // Move word right includes space/punctuation.
+#if BUILDFLAG(IS_WIN) // Move word right includes space/punctuation.
expected.push_back(Range(4));
expected.push_back(Range(8));
#else // Non-Windows: move word right does NOT include space/punctuation.
@@ -2832,7 +2836,7 @@
// Move right twice.
expected.push_back(Range(6));
-#if defined(OS_WIN) // Select word right includes space/punctuation.
+#if BUILDFLAG(IS_WIN) // Select word right includes space/punctuation.
expected.push_back(Range(6, 8));
#else // Non-Windows: select word right does NOT include space/punctuation.
expected.push_back(Range(6, 7));
@@ -2854,7 +2858,7 @@
SELECTION_RETAIN, &expected);
// Move right twice.
-#if defined(OS_WIN) // Select word right includes space/punctuation.
+#if BUILDFLAG(IS_WIN) // Select word right includes space/punctuation.
expected.push_back(Range(6, 8));
#else // Non-Windows: select word right does NOT include space/punctuation.
expected.push_back(Range(6, 7));
@@ -2877,7 +2881,7 @@
SELECTION_EXTEND, &expected);
// Move right twice.
-#if defined(OS_WIN) // Select word right includes space/punctuation.
+#if BUILDFLAG(IS_WIN) // Select word right includes space/punctuation.
expected.push_back(Range(4, 8));
#else // Non-Windows: select word right does NOT include space/punctuation.
expected.push_back(Range(4, 7));
@@ -2907,7 +2911,7 @@
SELECTION_NONE, &expected);
// Move left twice.
-#if defined(OS_WIN) // Move word left includes space/punctuation.
+#if BUILDFLAG(IS_WIN) // Move word left includes space/punctuation.
expected.push_back(Range(4));
expected.push_back(Range(8));
#else // Non-Windows: move word left does NOT include space/punctuation.
@@ -2927,7 +2931,7 @@
// Move left twice.
expected.push_back(Range(6));
-#if defined(OS_WIN) // Select word left includes space/punctuation.
+#if BUILDFLAG(IS_WIN) // Select word left includes space/punctuation.
expected.push_back(Range(6, 8));
#else // Non-Windows: select word left does NOT include space/punctuation.
expected.push_back(Range(6, 7));
@@ -2949,7 +2953,7 @@
SELECTION_RETAIN, &expected);
// Move left twice.
-#if defined(OS_WIN) // Select word left includes space/punctuation.
+#if BUILDFLAG(IS_WIN) // Select word left includes space/punctuation.
expected.push_back(Range(6, 8));
#else // Non-Windows: select word left does NOT include space/punctuation.
expected.push_back(Range(6, 7));
@@ -2972,7 +2976,7 @@
SELECTION_EXTEND, &expected);
// Move left twice.
-#if defined(OS_WIN) // Select word left includes space/punctuation.
+#if BUILDFLAG(IS_WIN) // Select word left includes space/punctuation.
expected.push_back(Range(4, 8));
#else // Non-Windows: select word left does NOT include space/punctuation.
expected.push_back(Range(4, 7));
@@ -3446,10 +3450,11 @@
base::i18n::RIGHT_TO_LEFT : base::i18n::LEFT_TO_RIGHT;
// Ensure that directionality modes yield the correct text directions.
- for (size_t j = 0; j < base::size(cases); j++) {
+ for (size_t j = 0; j < std::size(cases); j++) {
render_text->SetText(cases[j].text);
render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_TEXT);
- EXPECT_EQ(render_text->GetDisplayTextDirection(),cases[j].text_direction);
+ EXPECT_EQ(render_text->GetDisplayTextDirection(),
+ cases[j].text_direction);
render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_UI);
EXPECT_EQ(render_text->GetDisplayTextDirection(), ui_direction);
render_text->SetDirectionalityMode(DIRECTIONALITY_FORCE_LTR);
@@ -3943,7 +3948,7 @@
};
RenderText* render_text = GetRenderText();
- for (size_t i = 0; i < base::size(cases); i++) {
+ for (size_t i = 0; i < std::size(cases); i++) {
SCOPED_TRACE(base::StringPrintf("Testing cases[%" PRIuS "]", i));
render_text->SetText(cases[i].text);
@@ -3967,7 +3972,7 @@
RenderText* render_text = GetRenderText();
render_text->SetDisplayRect(Rect(100, 1000));
- for (size_t i = 0; i < base::size(cases); i++) {
+ for (size_t i = 0; i < std::size(cases); i++) {
SCOPED_TRACE(base::StringPrintf("Testing cases[%" PRIuS "]", i));
render_text->SetText(cases[i]);
EXPECT_TRUE(render_text->IsValidLogicalIndex(1));
@@ -3996,7 +4001,7 @@
const char16_t* kTestStrings[] = {kLtrRtl, kLtrRtlLtr, kRtlLtr, kRtlLtrRtl};
RenderText* render_text = GetRenderText();
render_text->SetDisplayRect(Rect(0, 0, 100, 20));
- for (size_t i = 0; i < base::size(kTestStrings); ++i) {
+ for (size_t i = 0; i < std::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("Testing case[%" PRIuS "]", i));
render_text->SetText(kTestStrings[i]);
for (size_t j = 0; j < render_text->text().length(); ++j) {
@@ -4140,7 +4145,7 @@
render_text->SetDisplayRect(Rect(25, 1000));
render_text->SetMultiline(true);
- for (size_t i = 0; i < base::size(kTestStrings); i++) {
+ for (size_t i = 0; i < std::size(kTestStrings); i++) {
render_text->SetText(kTestStrings[i]);
EXPECT_EQ(2u, render_text->GetNumLines());
@@ -4181,7 +4186,7 @@
RenderText* render_text = GetRenderText();
render_text->SetDisplayRect(gfx::Rect(100, 30));
- for (size_t i = 0; i < base::size(cases); i++) {
+ for (size_t i = 0; i < std::size(cases); i++) {
SCOPED_TRACE(base::StringPrintf("Testing case %" PRIuS "", i));
render_text->SetText(cases[i].text);
std::set<size_t> obtained_cursor_positions;
@@ -4218,7 +4223,7 @@
};
RenderText* render_text = GetRenderText();
- for (size_t i = 0; i < base::size(cases); i++) {
+ for (size_t i = 0; i < std::size(cases); i++) {
render_text->SetText(cases[i].text);
bool ltr = (cases[i].expected_text_direction == base::i18n::LEFT_TO_RIGHT);
@@ -4250,7 +4255,7 @@
EXPECT_EQ(render_text->selection_model(), SelectionModel());
// Test the weak, LTR, RTL, and Bidi string cases.
- for (size_t j = 0; j < base::size(cases); j++) {
+ for (size_t j = 0; j < std::size(cases); j++) {
render_text->SetText(cases[j]);
render_text->SelectAll(false);
EXPECT_EQ(render_text->selection_model(), expected_forwards);
@@ -4352,14 +4357,14 @@
// Move cursor right with WORD_BREAK.
render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, SELECTION_NONE);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
EXPECT_EQ(Range(4), render_text->selection());
#else
EXPECT_EQ(Range(3), render_text->selection());
#endif
EXPECT_EQ(0U, GetLineContainingCaret());
render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, SELECTION_NONE);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
EXPECT_EQ(Range(9), render_text->selection());
EXPECT_EQ(3U, GetLineContainingCaret());
#else
@@ -4410,7 +4415,7 @@
// Widen the display rect and, by checking the cursor bounds, make sure no
// empty space is introduced to the left of the text.
- display_rect.Inset(0, 0, -kEnlargement, 0);
+ display_rect.Inset(gfx::Insets::TLBR(0, 0, 0, -kEnlargement));
render_text->SetDisplayRect(display_rect);
EXPECT_EQ(display_rect.x(), render_text->GetUpdatedCursorBounds().x());
@@ -4422,7 +4427,7 @@
// Widen the display rect and, by checking the cursor bounds, make sure no
// empty space is introduced to the right of the text.
- display_rect.Inset(0, 0, -kEnlargement, 0);
+ display_rect.Inset(gfx::Insets::TLBR(0, 0, 0, -kEnlargement));
render_text->SetDisplayRect(display_rect);
EXPECT_EQ(display_rect.right(),
render_text->GetUpdatedCursorBounds().right());
@@ -4444,7 +4449,7 @@
const SelectionModel end = render_text->selection_model();
// For testing simplicity, each word is a 3-character word.
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Windows moves from "|abc def" to "abc |def" instead of "abc| def", so
// traverse 4 characters on all but the last word instead of all but the
// first.
@@ -4491,7 +4496,7 @@
}
}
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// TODO(aleventhal): https://crbug.com/906308 Fix bugs, update verifier code
// above, and enable for Windows.
#define MAYBE_MoveLeftRightByWordInBidiText \
@@ -4576,7 +4581,7 @@
render_text->SetText(u"abc def");
render_text->SetCursorPosition(5);
render_text->MoveCursor(WORD_BREAK, CURSOR_RIGHT, SELECTION_NONE);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
EXPECT_EQ(8U, render_text->cursor_position());
#else
EXPECT_EQ(11U, render_text->cursor_position());
@@ -4614,7 +4619,7 @@
// TODO(crbug.com/865527): Chinese and Japanese tokenization doesn't work on
// mobile.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
TEST_F(RenderTextTest, MoveLeftRightByWordInChineseText) {
RenderText* render_text = GetRenderText();
// zh-Hans-CN: 我们去公园玩, broken to 我们|去|公园|玩.
@@ -4959,7 +4964,7 @@
RenderText* render_text = GetRenderText();
render_text->SetText(u"A quick brown fox jumped over the lazy dog!");
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
const FontList body2_font = FontList().DeriveWithSizeDelta(-1);
#else
const FontList body2_font;
@@ -4968,7 +4973,7 @@
const FontList headline_font = body2_font.DeriveWithSizeDelta(8);
const FontList title_font = body2_font.DeriveWithSizeDelta(3);
const FontList body1_font = body2_font.DeriveWithSizeDelta(1);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
const FontList button_font =
body2_font.DeriveWithWeight(gfx::Font::Weight::BOLD);
#else
@@ -5154,10 +5159,10 @@
// implemented because of test system font configuration).
RenderText* render_text = GetRenderText();
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
// Increase font size to ensure that bold and regular styles differ in width.
render_text->SetFontList(FontList("Arial, 20px"));
-#endif // defined(OS_FUCHSIA)
+#endif // BUILDFLAG(IS_FUCHSIA)
render_text->SetText(u"Hello World");
@@ -5169,7 +5174,7 @@
const int bold_width = render_text->GetStringSize().width();
EXPECT_GT(bold_width, plain_width);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
render_text->SetWeight(Font::Weight::SEMIBOLD);
const int semibold_width = render_text->GetStringSize().width();
EXPECT_GT(bold_width, semibold_width);
@@ -5194,7 +5199,7 @@
const FontList& larger_font_list = default_font_list.DeriveWithSizeDelta(24);
EXPECT_GT(larger_font_list.GetHeight(), default_font_list.GetHeight());
- for (size_t i = 0; i < base::size(cases); i++) {
+ for (size_t i = 0; i < std::size(cases); i++) {
ResetRenderTextInstance();
RenderText* render_text = GetRenderText();
render_text->SetFontList(default_font_list);
@@ -5242,7 +5247,7 @@
render_text->SetVerticalAlignment(ALIGN_TOP);
static const size_t kGraphemeBoundaries[] = {0, 2, 4, 6, 7};
- for (size_t i = 0; i < base::size(kGraphemeBoundaries); ++i) {
+ for (size_t i = 0; i < std::size(kGraphemeBoundaries); ++i) {
const size_t text_offset = kGraphemeBoundaries[i];
EXPECT_EQ(render_text->GetCursorBounds(
SelectionModel(text_offset, CURSOR_FORWARD), true),
@@ -5285,7 +5290,7 @@
EXPECT_TRUE(offset.IsZero());
const int kEnlargementX = 2;
- display_rect.Inset(0, 0, -kEnlargementX, 0);
+ display_rect.Inset(gfx::Insets::TLBR(0, 0, 0, -kEnlargementX));
render_text->SetDisplayRect(display_rect);
// Check the default horizontal alignment.
@@ -5305,10 +5310,10 @@
// Check that text is vertically centered within taller display rects.
const int kEnlargementY = display_rect.height();
- display_rect.Inset(0, 0, 0, -kEnlargementY);
+ display_rect.Inset(gfx::Insets::TLBR(0, 0, -kEnlargementY, 0));
render_text->SetDisplayRect(display_rect);
const Vector2d prev_offset = render_text->GetLineOffset(0);
- display_rect.Inset(0, 0, 0, -2 * kEnlargementY);
+ display_rect.Inset(gfx::Insets::TLBR(0, 0, -2 * kEnlargementY, 0));
render_text->SetDisplayRect(display_rect);
offset = render_text->GetLineOffset(0);
EXPECT_EQ(prev_offset.y() + kEnlargementY, offset.y());
@@ -5353,7 +5358,7 @@
EXPECT_TRUE(offset.IsZero());
const int kEnlargementY = 10;
- display_rect.Inset(0, 0, 0, -kEnlargementY);
+ display_rect.Inset(gfx::Insets::TLBR(0, 0, -kEnlargementY, 0));
render_text->SetDisplayRect(display_rect);
// Check the default vertical alignment (ALIGN_MIDDLE).
@@ -5393,7 +5398,7 @@
EXPECT_TRUE(offset.IsZero());
const int kEnlargementY = 10;
- display_rect.Inset(0, 0, 0, -kEnlargementY);
+ display_rect.Inset(gfx::Insets::TLBR(0, 0, -kEnlargementY, 0));
render_text->SetDisplayRect(display_rect);
// Check the default vertical alignment (ALIGN_MIDDLE).
@@ -5425,7 +5430,7 @@
// different possible situations. In this case the only possible display
// offset is zero.
Rect display_rect(font_size);
- display_rect.Inset(0, 0, -kEnlargement, 0);
+ display_rect.Inset(gfx::Insets::TLBR(0, 0, 0, -kEnlargement));
render_text->SetDisplayRect(display_rect);
struct {
@@ -5443,7 +5448,7 @@
{ ALIGN_CENTER, kEnlargement },
};
- for (size_t i = 0; i < base::size(small_content_cases); i++) {
+ for (size_t i = 0; i < std::size(small_content_cases); i++) {
render_text->SetHorizontalAlignment(small_content_cases[i].alignment);
render_text->SetDisplayOffset(small_content_cases[i].offset);
EXPECT_EQ(0, render_text->GetUpdatedDisplayOffset().x());
@@ -5452,7 +5457,7 @@
// Set display width |kEnlargement| pixels less than content width and test
// different possible situations.
display_rect = Rect(font_size);
- display_rect.Inset(0, 0, kEnlargement, 0);
+ display_rect.Inset(gfx::Insets::TLBR(0, 0, 0, kEnlargement));
render_text->SetDisplayRect(display_rect);
struct {
@@ -5478,7 +5483,7 @@
{ ALIGN_CENTER, kEnlargement, (kEnlargement - 1) / 2 },
};
- for (size_t i = 0; i < base::size(large_content_cases); i++) {
+ for (size_t i = 0; i < std::size(large_content_cases); i++) {
render_text->SetHorizontalAlignment(large_content_cases[i].alignment);
render_text->SetDisplayOffset(large_content_cases[i].offset);
EXPECT_EQ(large_content_cases[i].expected_offset,
@@ -5526,14 +5531,14 @@
};
RenderText* render_text = GetRenderText();
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
std::u16string text = cases[i].text;
const size_t start_paren_char_index = text.find('(');
ASSERT_NE(std::u16string::npos, start_paren_char_index);
const size_t end_paren_char_index = text.find(')');
ASSERT_NE(std::u16string::npos, end_paren_char_index);
- for (size_t j = 0; j < base::size(punctuation_pairs); ++j) {
+ for (size_t j = 0; j < std::size(punctuation_pairs); ++j) {
text[start_paren_char_index] = punctuation_pairs[j].left_char;
text[end_paren_char_index] = punctuation_pairs[j].right_char;
render_text->SetText(text);
@@ -5596,7 +5601,7 @@
{ 16, 13, 16 },
};
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
render_text->SetCursorPosition(cases[i].cursor);
render_text->SelectWord();
EXPECT_EQ(Range(cases[i].selection_start, cases[i].selection_end),
@@ -5763,7 +5768,7 @@
RenderText* render_text = GetRenderText();
render_text->set_selection_color(SK_ColorGREEN);
- for (size_t i = 0; i < base::size(kTestStrings); ++i) {
+ for (size_t i = 0; i < std::size(kTestStrings); ++i) {
render_text->SetText(kTestStrings[i]);
const int expected_width = render_text->GetStringSize().width();
render_text->SelectRange({0, 1});
@@ -5828,7 +5833,7 @@
render_text->SetMultiline(true);
render_text->SetWordWrapBehavior(WRAP_LONG_WORDS);
- for (size_t i = 0; i < base::size(kTestStrings); ++i) {
+ for (size_t i = 0; i < std::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(kTestStrings[i]);
render_text->Draw(canvas());
@@ -5883,7 +5888,7 @@
render_text->SetWordWrapBehavior(WRAP_LONG_WORDS);
render_text->SetHorizontalAlignment(ALIGN_TO_HEAD);
- for (size_t i = 0; i < base::size(kTestStrings); ++i) {
+ for (size_t i = 0; i < std::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(kTestStrings[i].text);
DrawVisualText();
@@ -5932,7 +5937,7 @@
render_text->SetDisplayRect(Rect(1000, 1000));
render_text->SetMultiline(true);
- for (size_t i = 0; i < base::size(kTestStrings); ++i) {
+ for (size_t i = 0; i < std::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(kTestStrings[i]);
render_text->Draw(canvas());
@@ -5959,7 +5964,7 @@
render_text->SetDisplayRect(Rect(200, 1000));
render_text->SetMultiline(true);
- for (size_t i = 0; i < base::size(kTestStrings); ++i) {
+ for (size_t i = 0; i < std::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(kTestStrings[i].text);
render_text->Draw(canvas());
@@ -6002,7 +6007,7 @@
u"abc\ndef", u"a \n b ", u"ab\n", u"a\n\nb", u"\nab", u"\n",
};
- for (size_t i = 0; i < base::size(kTestStrings); ++i) {
+ for (size_t i = 0; i < std::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
ResetRenderTextInstance();
RenderText* render_text = GetRenderText();
@@ -6054,7 +6059,7 @@
render_text->SetDisplayRect(Rect(100, 1000));
render_text->SetMultiline(true);
- for (size_t i = 0; i < base::size(kTestStrings); ++i) {
+ for (size_t i = 0; i < std::size(kTestStrings); ++i) {
SCOPED_TRACE(testing::Message("kTestStrings[")
<< i << "] = " << kTestStrings[i].text);
render_text->SetText(kTestStrings[i].text);
@@ -6109,7 +6114,7 @@
SetGlyphWidth(kGlyphSize);
render_text->SetDisplayRect(Rect(0, 0, kGlyphSize * 4, 0));
- for (size_t i = 0; i < base::size(kTestScenarios); ++i) {
+ for (size_t i = 0; i < std::size(kTestScenarios); ++i) {
SCOPED_TRACE(base::StringPrintf(
"kTestScenarios[%" PRIuS "] %d", i, kTestScenarios[i].behavior));
render_text->SetWordWrapBehavior(kTestScenarios[i].behavior);
@@ -6177,7 +6182,7 @@
SetGlyphWidth(kGlyphSize);
render_text->SetDisplayRect(Rect(0, 0, kGlyphSize * 4, 0));
- for (size_t i = 0; i < base::size(kTestScenarios); ++i) {
+ for (size_t i = 0; i < std::size(kTestScenarios); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(kTestScenarios[i].text);
render_text->SetWordWrapBehavior(kTestScenarios[i].behavior);
@@ -6240,7 +6245,7 @@
{Range(0, 2), Range(2, 3), Range(3, 5)}},
};
- for (size_t i = 0; i < base::size(kTestScenarios); ++i) {
+ for (size_t i = 0; i < std::size(kTestScenarios); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(kTestScenarios[i].text);
render_text->SetDisplayRect(Rect(0, 0, kTestScenarios[i].display_width, 0));
@@ -6274,7 +6279,7 @@
EXPECT_EQ(3u, test_api()->lines().size());
for (size_t j = 0;
- j < std::min(base::size(char_ranges), test_api()->lines().size()); ++j) {
+ j < std::min(std::size(char_ranges), test_api()->lines().size()); ++j) {
SCOPED_TRACE(base::StringPrintf("%" PRIuS "-th line", j));
int segment_size = test_api()->lines()[j].segments.size();
ASSERT_GT(segment_size, 0);
@@ -6283,6 +6288,16 @@
test_api()->lines()[j].segments[segment_size - 1].char_range.end());
EXPECT_EQ(char_ranges[j], line_range);
}
+
+ for (const std::u16string test_text : {u"\u200b", u"A\u200bB", u"A\u200b"}) {
+ for (int width = 1; width <= 5; width++) {
+ SCOPED_TRACE(testing::Message()
+ << "String: '" << test_text << "' width: " << width);
+ render_text->SetText(test_text);
+ render_text->SetDisplayRect(Rect(0, 0, width, 0));
+ render_text->Draw(canvas());
+ }
+ }
}
TEST_F(RenderTextTest, Multiline_ZeroWidthNewline) {
@@ -6356,7 +6371,7 @@
RenderText* render_text = GetRenderText();
render_text->SetDisplayRect(Rect(200, 1000));
- for (size_t i = 0; i < base::size(kTestStrings); ++i) {
+ for (size_t i = 0; i < std::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(kTestStrings[i]);
render_text->Draw(canvas());
@@ -6372,16 +6387,28 @@
render_text->SetText(kTextWithControlCharacters);
// The control characters should have been replaced by their symbols.
- EXPECT_EQ(u"␈␍␇␉␊␋␌", render_text->GetDisplayText());
+ EXPECT_EQ(u"␈␍␇⇥ ␋␌", render_text->GetDisplayText());
// Setting multiline, the newline character will be back to the original text.
render_text->SetMultiline(true);
- EXPECT_EQ(u"␈\r␇␉\n␋␌", render_text->GetDisplayText());
+ EXPECT_EQ(u"␈\r␇⇥\n␋␌", render_text->GetDisplayText());
// The generic control characters should have been replaced by the replacement
// codepoints.
render_text->SetText(u"\u008f\u0080");
EXPECT_EQ(u"\ufffd\ufffd", render_text->GetDisplayText());
+
+ // The '\r\n' should have been replaced with single CR symbol in single line
+ // mode, even if it's a trailing newline.
+ render_text->SetMultiline(false);
+ render_text->SetText(u"abc\r\n\r\n");
+ EXPECT_EQ(u"abc␍ ␍ ", render_text->GetDisplayText());
+ render_text->SetText(u"abc\r\n");
+ EXPECT_EQ(u"abc␍ ", render_text->GetDisplayText());
+
+ // The trailing '\r\n' should not be replaced in multi line mode.
+ render_text->SetMultiline(true);
+ EXPECT_EQ(u"abc\r\n", render_text->GetDisplayText());
}
TEST_F(RenderTextTest, PrivateUseCharacterReplacement) {
@@ -6402,7 +6429,7 @@
// see: http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/CORPCHAR.TXT
RenderText* render_text = GetRenderText();
render_text->SetText(u"\uf8ff");
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
EXPECT_EQ(u"\uf8ff", render_text->GetDisplayText());
#else
EXPECT_EQ(u"\ufffd", render_text->GetDisplayText());
@@ -6417,12 +6444,8 @@
for (auto* codepoint : allowed_codepoints) {
RenderText* render_text = GetRenderText();
render_text->SetText(codepoint);
-#if defined(OS_WIN)
- if (base::win::GetVersion() >= base::win::Version::WIN10) {
- EXPECT_EQ(codepoint, render_text->GetDisplayText());
- } else {
- EXPECT_EQ(u"\uFFFD", render_text->GetDisplayText());
- }
+#if BUILDFLAG(IS_WIN)
+ EXPECT_EQ(codepoint, render_text->GetDisplayText());
#else
EXPECT_EQ(u"\uFFFD", render_text->GetDisplayText());
#endif
@@ -6449,7 +6472,7 @@
RenderTextHarfBuzz* render_text = GetRenderText();
- for (size_t i = 0; i < base::size(kTestStrings); ++i) {
+ for (size_t i = 0; i < std::size(kTestStrings); ++i) {
SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i));
render_text->SetText(kTestStrings[i].text);
@@ -6512,9 +6535,8 @@
run.shape.glyph_count = 4;
run.shape.glyph_to_char.resize(4);
- for (size_t i = 0; i < base::size(cases); ++i) {
- std::copy(cases[i].glyph_to_char, cases[i].glyph_to_char + 4,
- run.shape.glyph_to_char.begin());
+ for (size_t i = 0; i < std::size(cases); ++i) {
+ base::ranges::copy(cases[i].glyph_to_char, run.shape.glyph_to_char.begin());
run.font_params.is_rtl = cases[i].is_rtl;
for (size_t j = 0; j < 4; ++j) {
@@ -6555,7 +6577,7 @@
RenderTextHarfBuzz* render_text = GetRenderText();
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
SCOPED_TRACE(base::StringPrintf("Case %" PRIuS, i));
std::u16string text = cases[i];
@@ -6610,9 +6632,8 @@
RenderTextHarfBuzz* render_text = GetRenderText();
render_text->SetText(u"abcd");
- for (size_t i = 0; i < base::size(cases); ++i) {
- std::copy(cases[i].glyph_to_char, cases[i].glyph_to_char + 2,
- run.shape.glyph_to_char.begin());
+ for (size_t i = 0; i < std::size(cases); ++i) {
+ base::ranges::copy(cases[i].glyph_to_char, run.shape.glyph_to_char.begin());
run.font_params.is_rtl = cases[i].is_rtl;
for (int j = 0; j < 2; ++j)
run.shape.positions[j].set(j * 10, 0);
@@ -6752,15 +6773,8 @@
EXPECT_EQ(gfx::Range(1, 1), render_text->selection());
EXPECT_EQ(1 * kGlyphWidth, render_text->GetUpdatedCursorBounds().x());
-#if defined(OS_APPLE)
- // Early versions of macOS provide a tofu glyph for the variation selector.
- // Bail out early except on 10.12 and above.
- if (base::mac::IsAtMostOS10_11())
- return;
-#endif
-
// TODO(865709): make this work on Android.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Jump over the telephone: two codepoints, but a single glyph.
render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, SELECTION_NONE);
EXPECT_EQ(gfx::Range(3, 3), render_text->selection());
@@ -6790,7 +6804,7 @@
TEST_F(RenderTextTest, HarfBuzz_AsciiVariationSelector) {
RenderTextHarfBuzz* render_text = GetRenderText();
-#if defined(OS_APPLE)
+#if BUILDFLAG(IS_APPLE)
// Don't use a system font on macOS - asking for a variation selector on
// ASCII glyphs can tickle OS bugs. See http://crbug.com/785522.
render_text->SetFontList(FontList("Arial, 12px"));
@@ -6884,10 +6898,10 @@
const internal::TextRunList* run_list = GetHarfBuzzRunList();
ASSERT_EQ(1U, run_list->runs().size());
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_APPLE)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_APPLE)
// On Linux and macOS, the flags should be found, so two glyphs result.
EXPECT_EQ(2u, run_list->runs()[0]->shape.glyph_count);
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
// It seems that some versions of android support the flags. Older versions
// don't support it.
EXPECT_TRUE(2u == run_list->runs()[0]->shape.glyph_count ||
@@ -6916,12 +6930,9 @@
EXPECT_EQ(expected, GetRunListStrings());
EXPECT_EQ("[0->2][3][4->6]", GetRunListStructureString());
-#if defined(OS_WIN)
- std::vector<std::string> expected_fonts;
- if (base::win::GetVersion() < base::win::Version::WIN10)
- expected_fonts = {"Segoe UI", "Segoe UI", "Segoe UI Symbol"};
- else
- expected_fonts = {"Segoe UI Emoji", "Segoe UI", "Segoe UI Symbol"};
+#if BUILDFLAG(IS_WIN)
+ const std::vector<std::string> expected_fonts = {"Segoe UI Emoji", "Segoe UI",
+ "Segoe UI Symbol"};
std::vector<std::string> mapped_fonts;
for (const auto& font_span : GetFontSpans())
@@ -6935,7 +6946,7 @@
u"\u0645\u0631\u062D\u0628\u0627"};
RenderText* render_text = GetRenderText();
- for (size_t i = 0; i < base::size(kTestStrings); ++i) {
+ for (size_t i = 0; i < std::size(kTestStrings); ++i) {
render_text->SetText(kTestStrings[i]);
for (size_t j = 0; j < render_text->text().length(); ++j)
@@ -7004,7 +7015,7 @@
}
// TODO(865715): Figure out why this fails on Android.
-#if !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_ANDROID)
// Ensure that RenderText examines all of the fonts in its FontList before
// falling back to other fonts.
TEST_F(RenderTextTest, HarfBuzz_FontListFallback) {
@@ -7027,13 +7038,13 @@
ASSERT_EQ(static_cast<size_t>(1), spans.size());
EXPECT_EQ(kSymbolFontName, spans[0].first.GetFontName());
}
-#endif // !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_ANDROID)
// Ensure that the fallback fonts offered by GetFallbackFonts() are tried. Note
// this test assumes the font "Arial" doesn't provide a unicode glyph for a
// particular character, and that there is a system fallback font which does.
// TODO(msw): Fallback doesn't find a glyph on Linux and Android.
-#if !defined(OS_LINUX) && !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+#if !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)
TEST_F(RenderTextTest, HarfBuzz_UnicodeFallback) {
RenderTextHarfBuzz* render_text = GetRenderText();
render_text->SetFontList(FontList("Arial, 12px"));
@@ -7044,7 +7055,8 @@
ASSERT_EQ(1U, run_list->size());
EXPECT_EQ(0U, run_list->runs()[0]->CountMissingGlyphs());
}
-#endif // !defined(OS_LINUX) && !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+#endif // !BUILDFLAG(IS_LINUX) && !BUILDFLAG(IS_CHROMEOS) &&
+ // !BUILDFLAG(IS_ANDROID)
// Ensure that the fallback fonts offered by GetFallbackFont() support glyphs
// for different languages.
@@ -7154,7 +7166,7 @@
{"mixed1", u"www.اختبار.com"},
{"mixed2", u"(اختبار)"},
{"mixed3", u"/ זה (מבחן) /"},
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
{"asc_arb", u"abcښڛڜdef"},
{"devanagari", u"ञटठडढणतथ"},
{"ethiopic", u"መጩጪᎅⶹⶼ"},
@@ -7215,7 +7227,7 @@
// block. These tests work on Windows and Mac default fonts installation.
// On other platforms, the fonts are mock (see test_fonts).
const FallbackFontCase kCommonScriptCases[] = {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// The following tests are made to work on win7 and win10.
{"common00", u"\u237b\u2ac1\u24f5\u259f\u2a87\u23ea\u25d4\u2220"},
{"common01", u"\u2303\u2074\u2988\u32b6\u26a2\u24e5\u2a53\u2219"},
@@ -7249,7 +7261,7 @@
{"common29", u"\u2981\ua721\u25a9\u2320\u21cf\u295a\u2273\u2ac2"},
{"common30", u"\u22d9\u2465\u2347\u2a94\u4dca\u2389\u23b0\u208d"},
{"common31", u"\u21cc\u2af8\u2912\u23a4\u2271\u2303\u241e\u33a1"},
-#elif defined(OS_ANDROID)
+#elif BUILDFLAG(IS_ANDROID)
{"common00", u"\u2497\uff04\u277c\u21b6\u2076\u21e4\u2068\u21b3"},
{"common01", u"\u2663\u2466\u338e\u226b\u2734\u21be\u3389\u00ab"},
{"common02", u"\u2062\u2197\u3392\u2681\u33be\u206d\ufe10\ufe34"},
@@ -7282,7 +7294,7 @@
{"common29", u"\u2517\u2297\u2762\u2460\u25bd\u24a9\u21a7\ufe64"},
{"common30", u"\u2105\u2722\u275d\u249c\u21a2\u2590\u2260\uff5d"},
{"common31", u"\u33ba\u21c6\u2706\u02cb\ufe64\u02e6\u0374\u2493"},
-#elif defined(OS_APPLE)
+#elif BUILDFLAG(IS_APPLE)
{"common00", u"\u2153\u24e0\u2109\u02f0\u2a8f\u25ed\u02c5\u2716"},
{"common01", u"\u02f0\u208c\u2203\u2518\u2067\u2270\u21f1\ufe66"},
{"common02", u"\u2686\u2585\u2b15\u246f\u23e3\u21b4\u2394\ufe31"},
@@ -7329,7 +7341,7 @@
::testing::ValuesIn(kCommonScriptCases),
RenderTextTestWithFallbackFontCase::ParamInfoToString);
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Ensures that locale is used for fonts selection.
TEST_F(RenderTextTest, CJKFontWithLocale) {
const char16_t kCJKTest[] = u"\u8AA4\u904E\u9AA8";
@@ -7352,7 +7364,7 @@
EXPECT_TRUE(unique_font_name);
}
}
-#endif // defined(OS_WIN)
+#endif // BUILDFLAG(IS_WIN)
TEST_F(RenderTextTest, SameFontAccrossIgnorableCodepoints) {
RenderText* render_text = GetRenderText();
@@ -7415,7 +7427,7 @@
render_text->SetColor(SK_ColorBLACK);
for (auto* string : kTestStrings) {
- paint_canvas.clear(SK_ColorWHITE);
+ paint_canvas.clear(SkColors::kWhite);
render_text->SetText(base::UTF8ToUTF16(string));
render_text->ApplyBaselineStyle(SUPERSCRIPT, Range(1, 2));
render_text->ApplyBaselineStyle(SUPERIOR, Range(3, 4));
@@ -7486,7 +7498,7 @@
render_text->SetColor(SK_ColorBLACK);
for (auto* string : kTestStrings) {
- paint_canvas.clear(SK_ColorWHITE);
+ paint_canvas.clear(SkColors::kWhite);
render_text->SetText(base::UTF8ToUTF16(string));
const Size string_size = render_text->GetStringSize();
int fake_width = string_size.width() / 2;
@@ -7578,8 +7590,8 @@
render_text->SetText(u"x");
DrawVisualText();
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || \
- defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \
+ BUILDFLAG(IS_FUCHSIA)
// On Linux, whether subpixel AA is supported is determined by the platform
// FontConfig. Force it into a particular style after computing runs. Other
// platforms use a known default FontRenderParams from a static local.
@@ -7589,12 +7601,23 @@
FontRenderParams::SUBPIXEL_RENDERING_RGB;
DrawVisualText();
#endif
+
+#if !BUILDFLAG(IS_MAC)
EXPECT_EQ(GetRendererFont().getEdging(), SkFont::Edging::kSubpixelAntiAlias);
+#else
+ if (features::IsChromeRefresh2023() &&
+ !base::FeatureList::IsEnabled(features::kCr2023MacFontSmoothing)) {
+ EXPECT_EQ(GetRendererFont().getEdging(), SkFont::Edging::kAntiAlias);
+ } else {
+ EXPECT_EQ(GetRendererFont().getEdging(),
+ SkFont::Edging::kSubpixelAntiAlias);
+ }
+#endif
render_text->set_subpixel_rendering_suppressed(true);
DrawVisualText();
-#if defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_ANDROID) || \
- defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \
+ BUILDFLAG(IS_FUCHSIA)
// For Linux, runs shouldn't be re-calculated, and the suppression of the
// SUBPIXEL_RENDERING_RGB set above should now take effect. But, after
// checking, apply the override anyway to be explicit that it is suppressed.
@@ -8032,7 +8055,7 @@
render_text->SetMultiline(true);
render_text->SetDisplayRect(Rect(20, 1000));
- for (size_t i = 0; i < base::size(cases); i++) {
+ for (size_t i = 0; i < std::size(cases); i++) {
SCOPED_TRACE(base::StringPrintf("Testing case %" PRIuS "", i));
render_text->SetText(cases[i].text);
@@ -8524,7 +8547,7 @@
ExpectTextLog(kUnselected);
}
-#if defined(OS_LINUX) || defined(OS_CHROMEOS)
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
TEST_F(RenderTextTest, StringSizeUpdatedWhenDeviceScaleFactorChanges) {
RenderText* render_text = GetRenderText();
render_text->SetText(u"Test - 1");
@@ -8549,6 +8572,59 @@
}
#endif
+// This test case is a unit test version of the clusterfuzz issue found in
+// crbug.com/1298286, an integer-overflow undefined behavior.
+TEST_F(RenderTextTest, Clusterfuzz_Issue_1298286) {
+ gfx::FontList::SetDefaultFontDescription("Arial, Times New Roman, 15px");
+
+ gfx::FontList font_list;
+ gfx::Rect field(2119635455, font_list.GetHeight());
+
+ RenderText* render_text = GetRenderText();
+ render_text->SetFontList(font_list);
+ render_text->SetHorizontalAlignment(ALIGN_RIGHT);
+ render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_UI);
+ render_text->SetText(u"t:");
+ render_text->SetDisplayRect(field);
+ render_text->SetCursorEnabled(true);
+
+ gfx::test::RenderTextTestApi render_text_test_api(render_text);
+ render_text_test_api.SetGlyphWidth(2016371456);
+
+ EXPECT_FALSE(render_text->multiline());
+
+ auto substring_bounds = render_text->GetSubstringBounds(gfx::Range(0, 2));
+
+ EXPECT_EQ(1UL, substring_bounds.size());
+ // Before the fix in crbug.com/1298286, this rect's x member would be -1
+ // because of undefined behavior due to integer overflow.
+ EXPECT_EQ(0, substring_bounds[0].x());
+}
+
+// This test case is a unit test version of the clusterfuzz issue found in
+// crbug.com/1299054, an integer-overflow undefined behavior.
+TEST_F(RenderTextTest, Clusterfuzz_Issue_1299054) {
+ gfx::FontList::SetDefaultFontDescription("Arial, Times New Roman, 15px");
+
+ gfx::FontList font_list;
+ gfx::Rect field(-1334808765, font_list.GetHeight());
+
+ RenderText* render_text = GetRenderText();
+ render_text->SetFontList(font_list);
+ render_text->SetHorizontalAlignment(ALIGN_CENTER);
+ render_text->SetDirectionalityMode(DIRECTIONALITY_FROM_TEXT);
+ render_text->SetText(u"s:");
+ render_text->SetDisplayRect(field);
+ render_text->SetCursorEnabled(false);
+
+ gfx::test::RenderTextTestApi render_text_test_api(render_text);
+ render_text_test_api.SetGlyphWidth(1778384896);
+
+ const Vector2d& offset = render_text->GetUpdatedDisplayOffset();
+ EXPECT_EQ(0, offset.x());
+ EXPECT_EQ(0, offset.y());
+}
+
TEST_F(RenderTextTest, Clusterfuzz_Issue_1287804) {
RenderText* render_text = GetRenderText();
render_text->SetMaxLines(1);
@@ -8559,4 +8635,15 @@
EXPECT_EQ(RangeF(0, 0), render_text->GetCursorSpan(Range(0, 0)));
}
+TEST_F(RenderTextTest, Clusterfuzz_Issue_1193815) {
+ RenderText* render_text = GetRenderText();
+ gfx::FontList font_list;
+ render_text->SetFontList(font_list);
+ render_text->Draw(canvas());
+ render_text->SetText(u"F\r");
+ render_text->SetMaxLines(1);
+ render_text->SetMultiline(true);
+ render_text->Draw(canvas());
+}
+
} // namespace gfx
diff --git a/ui/gfx/rendering_pipeline.cc b/ui/gfx/rendering_pipeline.cc
deleted file mode 100644
index 174b10b..0000000
--- a/ui/gfx/rendering_pipeline.cc
+++ /dev/null
@@ -1,298 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/rendering_pipeline.h"
-
-#include "base/containers/flat_map.h"
-#include "base/task/current_thread.h"
-#include "base/task/sequence_manager/task_time_observer.h"
-#include "base/thread_annotations.h"
-#include "base/threading/thread_checker.h"
-#include "ui/gfx/rendering_stage_scheduler.h"
-
-namespace gfx {
-namespace {
-
-class ThreadSafeTimeObserver : public base::sequence_manager::TaskTimeObserver {
- public:
- explicit ThreadSafeTimeObserver(
- scoped_refptr<base::SingleThreadTaskRunner> task_runner)
- : task_runner_(std::move(task_runner)) {}
- ~ThreadSafeTimeObserver() override {
- // If the observer is being used on the target thread, unregister now. If it
- // was being used on a different thread, then the target thread should have
- // been torn down already.
- SetEnabled(false);
- }
-
- ThreadSafeTimeObserver(const ThreadSafeTimeObserver&) = delete;
- ThreadSafeTimeObserver& operator=(const ThreadSafeTimeObserver&) = delete;
-
- void SetEnabled(bool enabled) {
- {
- base::AutoLock hold(time_lock_);
- if (enabled_ == enabled)
- return;
- enabled_ = enabled;
- }
-
- if (!task_runner_)
- return;
-
- if (task_runner_->BelongsToCurrentThread()) {
- UpdateOnTargetThread(enabled);
- return;
- }
-
- task_runner_->PostTask(
- FROM_HERE, base::BindOnce(&ThreadSafeTimeObserver::UpdateOnTargetThread,
- base::Unretained(this), enabled));
- }
-
- base::TimeDelta GetAndResetTimeSinceLastFrame() {
- base::AutoLock hold(time_lock_);
-
- if (!start_time_active_task_.is_null()) {
- auto now = base::TimeTicks::Now();
- time_since_last_frame_ += now - start_time_active_task_;
- start_time_active_task_ = now;
- }
-
- auto result = time_since_last_frame_;
- time_since_last_frame_ = base::TimeDelta();
- return result;
- }
-
- // TaskTimeObserver impl.
- void WillProcessTask(base::TimeTicks start_time) override {
- base::AutoLock hold(time_lock_);
- if (!enabled_)
- return;
-
- DCHECK(start_time_active_task_.is_null());
- start_time_active_task_ = start_time;
- }
-
- void DidProcessTask(base::TimeTicks start_time,
- base::TimeTicks end_time) override {
- base::AutoLock hold(time_lock_);
- if (!enabled_) {
- start_time_active_task_ = base::TimeTicks();
- return;
- }
-
- // This should be null for the task which adds this object to the observer
- // list.
- if (start_time_active_task_.is_null())
- return;
-
- if (start_time_active_task_ <= end_time) {
- time_since_last_frame_ += (end_time - start_time_active_task_);
- } else {
- // This could happen if |GetAndResetTimeSinceLastFrame| is called on a
- // different thread and the observed thread had to wait to acquire the
- // lock to call DidProcessTask. Assume the time for this task is already
- // recorded in |GetAndResetTimeSinceLastFrame|.
- DCHECK_NE(start_time_active_task_, start_time);
- }
-
- start_time_active_task_ = base::TimeTicks();
- }
-
- private:
- void UpdateOnTargetThread(bool enabled) {
- if (enabled) {
- base::CurrentThread::Get().AddTaskTimeObserver(this);
-
- base::AutoLock hold(time_lock_);
- start_time_active_task_ = base::TimeTicks();
- time_since_last_frame_ = base::TimeDelta();
- } else {
- base::CurrentThread::Get().RemoveTaskTimeObserver(this);
- }
- }
-
- // Accessed only on the calling thread. The caller ensures no concurrent
- // access.
- scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
-
- // Accessed on calling and target thread.
- base::Lock time_lock_;
- bool enabled_ GUARDED_BY(time_lock_) = false;
- base::TimeTicks start_time_active_task_ GUARDED_BY(time_lock_);
- base::TimeDelta time_since_last_frame_ GUARDED_BY(time_lock_);
-};
-
-} // namespace
-
-class RenderingPipelineImpl final : public RenderingPipeline {
- public:
- explicit RenderingPipelineImpl(const char* pipeline_type)
- : pipeline_type_(pipeline_type) {
- DETACH_FROM_THREAD(bound_thread_);
- }
- ~RenderingPipelineImpl() override { TearDown(); }
-
- RenderingPipelineImpl(const RenderingPipelineImpl&) = delete;
- RenderingPipelineImpl& operator=(const RenderingPipelineImpl&) = delete;
-
- void SetTargetDuration(base::TimeDelta target_duration) override {
- DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
- DCHECK(!target_duration.is_zero());
-
- if (target_duration_ == target_duration)
- return;
-
- target_duration_ = target_duration;
- if (should_use_scheduler())
- SetUp();
- }
-
- void AddSequenceManagerThread(
- base::PlatformThreadId thread_id,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) override {
- base::AutoLock lock(lock_);
- DCHECK(time_observers_.find(thread_id) == time_observers_.end());
- time_observers_[thread_id] =
- std::make_unique<ThreadSafeTimeObserver>(task_runner);
- if (scheduler_)
- CreateSchedulerAndEnableWithLockAcquired();
- }
-
- base::sequence_manager::TaskTimeObserver* AddSimpleThread(
- base::PlatformThreadId thread_id) override {
- base::AutoLock lock(lock_);
- DCHECK(time_observers_.find(thread_id) == time_observers_.end());
- time_observers_[thread_id] =
- std::make_unique<ThreadSafeTimeObserver>(nullptr);
-
- if (scheduler_)
- CreateSchedulerAndEnableWithLockAcquired();
- return time_observers_[thread_id].get();
- }
-
- void NotifyFrameFinished() override {
- DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
-
- base::AutoLock lock(lock_);
- if (!scheduler_)
- return;
-
- // TODO(crbug.com/1157620): This can be optimized to exclude tasks which can
- // be paused during rendering. The best use-case is idle tasks on the
- // renderer main thread. If all non-optional work is close to the frame
- // budget then the scheduler dynamically adjusts to pause work like idle
- // tasks.
- base::TimeDelta total_time;
- for (auto& it : time_observers_) {
- total_time += it.second->GetAndResetTimeSinceLastFrame();
- }
- scheduler_->ReportCpuCompletionTime(total_time + gpu_latency_);
- }
-
- void SetGpuLatency(base::TimeDelta gpu_latency) override {
- DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
- gpu_latency_ = gpu_latency;
- }
-
- void UpdateActiveCount(bool active) override {
- DCHECK_CALLED_ON_VALID_THREAD(bound_thread_);
-
- if (active) {
- active_count_++;
- } else {
- DCHECK_GT(active_count_, 0);
- active_count_--;
- }
-
- if (should_use_scheduler()) {
- SetUp();
- } else {
- TearDown();
- }
- }
-
- private:
- bool should_use_scheduler() const {
- // TODO(crbug.com/1157620) : Figure out what we should be doing if multiple
- // independent pipelines of a type are running simultaneously. The common
- // use-case for this in practice would be multi-window. The tabs could be
- // hosted in the same renderer process and each window is composited
- // independently by the GPU process.
- return active_count_ == 1 && !target_duration_.is_zero();
- }
-
- void SetUp() {
- base::AutoLock lock(lock_);
- CreateSchedulerAndEnableWithLockAcquired();
- }
-
- void CreateSchedulerAndEnableWithLockAcquired() {
- lock_.AssertAcquired();
- scheduler_.reset();
-
- std::vector<base::PlatformThreadId> platform_threads;
- for (auto& it : time_observers_) {
- platform_threads.push_back(it.first);
- it.second->SetEnabled(true);
- }
-
- scheduler_ = RenderingStageScheduler::CreateAdpf(
- pipeline_type_, std::move(platform_threads), target_duration_);
- }
-
- void TearDown() {
- base::AutoLock lock(lock_);
- for (auto& it : time_observers_)
- it.second->SetEnabled(false);
- scheduler_.reset();
- }
-
- THREAD_CHECKER(bound_thread_);
-
- base::Lock lock_;
- base::flat_map<base::PlatformThreadId,
- std::unique_ptr<ThreadSafeTimeObserver>>
- time_observers_ GUARDED_BY(lock_);
- std::unique_ptr<RenderingStageScheduler> scheduler_ GUARDED_BY(lock_);
-
- // Pipeline name, for tracing and metrics.
- const char* pipeline_type_;
-
- // The number of currently active pipelines of this type.
- int active_count_ = 0;
-
- // The target time for this rendering stage for a frame.
- base::TimeDelta target_duration_;
-
- base::TimeDelta gpu_latency_;
-};
-
-RenderingPipeline::ScopedPipelineActive::ScopedPipelineActive(
- RenderingPipeline* pipeline)
- : pipeline_(pipeline) {
- pipeline_->UpdateActiveCount(true);
-}
-
-RenderingPipeline::ScopedPipelineActive::~ScopedPipelineActive() {
- pipeline_->UpdateActiveCount(false);
-}
-
-std::unique_ptr<RenderingPipeline> RenderingPipeline::CreateRendererMain() {
- static constexpr char kRendererMain[] = "RendererMain";
- return std::make_unique<RenderingPipelineImpl>(kRendererMain);
-}
-
-std::unique_ptr<RenderingPipeline>
-RenderingPipeline::CreateRendererCompositor() {
- static constexpr char kRendererCompositor[] = "RendererCompositor";
- return std::make_unique<RenderingPipelineImpl>(kRendererCompositor);
-}
-
-std::unique_ptr<RenderingPipeline> RenderingPipeline::CreateGpu() {
- static constexpr char kGpu[] = "Gpu";
- return std::make_unique<RenderingPipelineImpl>(kGpu);
-}
-
-} // namespace gfx
diff --git a/ui/gfx/rendering_pipeline.h b/ui/gfx/rendering_pipeline.h
deleted file mode 100644
index 0ad6729..0000000
--- a/ui/gfx/rendering_pipeline.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_RENDERING_PIPELINE_H_
-#define UI_GFX_RENDERING_PIPELINE_H_
-
-#include "base/memory/singleton.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/platform_thread.h"
-#include "ui/gfx/gfx_export.h"
-
-namespace base {
-namespace sequence_manager {
-class TaskTimeObserver;
-}
-} // namespace base
-
-namespace gfx {
-
-// Tracks the desired and actual execution time of rendering threads to
-// optimally schedule them on the CPU. Instances of this class should be shared
-// between all compositors of the same rendering stage.
-//
-// This class can be created on any thread but becomes bound to the thread it's
-// subsequently used on. The class may be destroyed on any thread but the caller
-// is responsible for ensuring all other threads in the rendering stage, other
-// than the thread the object is destroyed on, are torn down before destroying
-// an instance of this class.
-class GFX_EXPORT RenderingPipeline {
- public:
- // Notifies when this pipeline is active. Multiple pipelines of the same type
- // can be concurrently active at a time. The pipeline is assumed active for
- // the lifetime of this object.
- class GFX_EXPORT ScopedPipelineActive {
- public:
- explicit ScopedPipelineActive(RenderingPipeline* pipeline);
- ~ScopedPipelineActive();
-
- private:
- RenderingPipeline* const pipeline_;
- };
-
- static std::unique_ptr<RenderingPipeline> CreateRendererMain();
- static std::unique_ptr<RenderingPipeline> CreateRendererCompositor();
- static std::unique_ptr<RenderingPipeline> CreateGpu();
-
- virtual ~RenderingPipeline() = default;
-
- // Add to this pipeline a thread backed by base sequence manager, where
- // |base::CurrentThread| works. Most threads in chromium should fall into
- // this category.
- // This method is thread safe and can be called on any thread.
- virtual void AddSequenceManagerThread(
- base::PlatformThreadId thread_id,
- scoped_refptr<base::SingleThreadTaskRunner> task_runner) = 0;
-
- // Add a simple thread to this pipeline. The caller is responsible for
- // updating the returned observer for tasks executed on the thread.
- // The returned observer is owned by this pipeline object.
- // This method is thread safe and can be called on any thread.
- virtual base::sequence_manager::TaskTimeObserver* AddSimpleThread(
- base::PlatformThreadId thread_id) = 0;
-
- // Notifies when this pipeline stage has finished rendering to compute the
- // execution time per frame for the associated threads.
- virtual void NotifyFrameFinished() = 0;
-
- // Sets the desired duration for this pipeline.
- virtual void SetTargetDuration(base::TimeDelta target_duration) = 0;
-
- // Sets the latency from composition for a display buffer finishing on the
- // Gpu thread to when execution finished on the Gpu.
- virtual void SetGpuLatency(base::TimeDelta delta) = 0;
-
- protected:
- virtual void UpdateActiveCount(bool active) = 0;
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_RENDERING_PIPELINE_H_
diff --git a/ui/gfx/rendering_stage_scheduler.cc b/ui/gfx/rendering_stage_scheduler.cc
deleted file mode 100644
index 0bfa2e0..0000000
--- a/ui/gfx/rendering_stage_scheduler.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/rendering_stage_scheduler.h"
-
-#include "base/logging.h"
-#include "base/no_destructor.h"
-#include "base/trace_event/trace_event.h"
-#include "build/build_config.h"
-
-#if defined(OS_ANDROID)
-#include "base/android/jni_array.h"
-#include "base/android/scoped_java_ref.h"
-#include "ui/gfx/gfx_jni_headers/AdpfRenderingStageScheduler_jni.h"
-#endif // OS_ANDROID
-
-namespace gfx {
-namespace {
-#if defined(OS_ANDROID)
-
-class RenderingStageSchedulerAdpf : public RenderingStageScheduler {
- public:
- RenderingStageSchedulerAdpf(const char* pipeline_type,
- std::vector<base::PlatformThreadId> threads,
- base::TimeDelta desired_duration)
- : pipeline_type_(pipeline_type), desired_duration_(desired_duration) {
- static_assert(sizeof(base::PlatformThreadId) == sizeof(jint),
- "thread id types incompatible");
- JNIEnv* env = base::android::AttachCurrentThread();
- j_object_ = Java_AdpfRenderingStageScheduler_create(
- env, base::android::ToJavaIntArray(env, threads),
- desired_duration_.InNanoseconds());
- }
-
- ~RenderingStageSchedulerAdpf() override {
- if (!j_object_)
- return;
- JNIEnv* env = base::android::AttachCurrentThread();
- Java_AdpfRenderingStageScheduler_destroy(env, j_object_);
- }
-
- void ReportCpuCompletionTime(base::TimeDelta actual_duration) override {
- TRACE_EVENT_INSTANT2(
- "benchmark", "RenderingStageSchedulerAdpf::ReportCpuCompletionTime",
- TRACE_EVENT_SCOPE_THREAD, "pipeline_type", pipeline_type_,
- "utilization_percentage",
- static_cast<int>(actual_duration * 100 / desired_duration_));
- if (!j_object_)
- return;
- JNIEnv* env = base::android::AttachCurrentThread();
- Java_AdpfRenderingStageScheduler_reportCpuCompletionTime(
- env, j_object_, actual_duration.InNanoseconds());
- }
-
- private:
- const char* pipeline_type_;
- const base::TimeDelta desired_duration_;
- base::android::ScopedJavaGlobalRef<jobject> j_object_;
-};
-
-#endif // OS_ANDROID
-
-} // namespace
-
-std::unique_ptr<RenderingStageScheduler> RenderingStageScheduler::CreateAdpf(
- const char* pipeline_type,
- std::vector<base::PlatformThreadId> threads,
- base::TimeDelta desired_duration) {
-#if defined(OS_ANDROID)
- return std::make_unique<RenderingStageSchedulerAdpf>(
- pipeline_type, std::move(threads), desired_duration);
-#else
- return nullptr;
-#endif
-}
-
-} // namespace gfx
diff --git a/ui/gfx/rendering_stage_scheduler.h b/ui/gfx/rendering_stage_scheduler.h
deleted file mode 100644
index 3c00f17..0000000
--- a/ui/gfx/rendering_stage_scheduler.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_RENDERING_STAGE_SCHEDULER_H_
-#define UI_GFX_RENDERING_STAGE_SCHEDULER_H_
-
-#include <memory>
-#include <vector>
-
-#include "base/threading/platform_thread.h"
-#include "ui/gfx/gfx_export.h"
-
-namespace gfx {
-
-class GFX_EXPORT RenderingStageScheduler {
- public:
- // Creating instances of this class requires loading native libraries which
- // require synchronous file access. This method ensures the synchronous work
- // is finished.
- static void EnsureInitialized();
-
- static std::unique_ptr<RenderingStageScheduler> CreateAdpf(
- const char* pipeline_type,
- std::vector<base::PlatformThreadId> threads,
- base::TimeDelta desired_duration);
-
- virtual ~RenderingStageScheduler() = default;
-
- virtual void ReportCpuCompletionTime(base::TimeDelta actual_duration) = 0;
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_RENDERING_STAGE_SCHEDULER_H_
diff --git a/ui/gfx/scoped_canvas.cc b/ui/gfx/scoped_canvas.cc
index fe45fcd..dc96e32 100644
--- a/ui/gfx/scoped_canvas.cc
+++ b/ui/gfx/scoped_canvas.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/scoped_canvas.h b/ui/gfx/scoped_canvas.h
index d2fee56..d20622e 100644
--- a/ui/gfx/scoped_canvas.h
+++ b/ui/gfx/scoped_canvas.h
@@ -1,11 +1,11 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_SCOPED_CANVAS_H_
#define UI_GFX_SCOPED_CANVAS_H_
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/gfx_export.h"
@@ -24,7 +24,7 @@
void FlipIfRTL(int width);
private:
- gfx::Canvas* canvas_;
+ raw_ptr<gfx::Canvas> canvas_;
};
} // namespace gfx
diff --git a/ui/gfx/scoped_cg_context_save_gstate_mac.h b/ui/gfx/scoped_cg_context_save_gstate_mac.h
index c829906..2f46059 100644
--- a/ui/gfx/scoped_cg_context_save_gstate_mac.h
+++ b/ui/gfx/scoped_cg_context_save_gstate_mac.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,8 +7,6 @@
#import <QuartzCore/QuartzCore.h>
-#include "base/macros.h"
-
namespace gfx {
class ScopedCGContextSaveGState {
diff --git a/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h b/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h
index b0e7553..a7f3a80 100644
--- a/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h
+++ b/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h
@@ -1,18 +1,13 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_SCOPED_NS_GRAPHICS_CONTEXT_SAVE_GSTATE_MAC_H_
#define UI_GFX_SCOPED_NS_GRAPHICS_CONTEXT_SAVE_GSTATE_MAC_H_
-#include "base/macros.h"
-#include "ui/gfx/gfx_export.h"
+#include <memory>
-#if defined(__OBJC__)
-@class NSGraphicsContext;
-#else
-class NSGraphicsContext;
-#endif
+#include "ui/gfx/gfx_export.h"
namespace gfx {
@@ -29,7 +24,8 @@
~ScopedNSGraphicsContextSaveGState();
private:
- NSGraphicsContext* context_; // weak
+ struct ObjCStorage;
+ std::unique_ptr<ObjCStorage> objc_storage_;
};
} // namespace gfx
diff --git a/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.mm b/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.mm
index 658f4c6..ee94ca7 100644
--- a/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.mm
+++ b/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,14 +10,19 @@
namespace gfx {
+struct ScopedNSGraphicsContextSaveGState::ObjCStorage {
+ NSGraphicsContext* context_; // weak
+};
+
ScopedNSGraphicsContextSaveGState::ScopedNSGraphicsContextSaveGState()
- : context_([NSGraphicsContext currentContext]) {
+ : objc_storage_(std::make_unique<ObjCStorage>()) {
+ objc_storage_->context_ = NSGraphicsContext.currentContext;
[NSGraphicsContext saveGraphicsState];
}
ScopedNSGraphicsContextSaveGState::~ScopedNSGraphicsContextSaveGState() {
[NSGraphicsContext restoreGraphicsState];
- DCHECK_EQ(context_, [NSGraphicsContext currentContext]);
+ DCHECK_EQ(objc_storage_->context_, NSGraphicsContext.currentContext);
}
} // namespace gfx
diff --git a/ui/gfx/scoped_ui_graphics_push_context_ios.h b/ui/gfx/scoped_ui_graphics_push_context_ios.h
index 682da30..48fb594 100644
--- a/ui/gfx/scoped_ui_graphics_push_context_ios.h
+++ b/ui/gfx/scoped_ui_graphics_push_context_ios.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,8 +7,6 @@
#import <QuartzCore/QuartzCore.h>
-#include "base/macros.h"
-
namespace gfx {
class ScopedUIGraphicsPushContext {
diff --git a/ui/gfx/scoped_ui_graphics_push_context_ios.mm b/ui/gfx/scoped_ui_graphics_push_context_ios.mm
index a5b9b95..5e2a3b3 100644
--- a/ui/gfx/scoped_ui_graphics_push_context_ios.mm
+++ b/ui/gfx/scoped_ui_graphics_push_context_ios.mm
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/scrollbar_size.cc b/ui/gfx/scrollbar_size.cc
index 040adec..3ef5f4d 100644
--- a/ui/gfx/scrollbar_size.cc
+++ b/ui/gfx/scrollbar_size.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright 2009 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,14 +7,14 @@
#include "base/compiler_specific.h"
#include "build/build_config.h"
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
#include <windows.h>
#endif
namespace gfx {
int scrollbar_size() {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
return GetSystemMetrics(SM_CXVSCROLL);
#else
return 15;
diff --git a/ui/gfx/scrollbar_size.h b/ui/gfx/scrollbar_size.h
index bfea069..7f9cf39 100644
--- a/ui/gfx/scrollbar_size.h
+++ b/ui/gfx/scrollbar_size.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/selection_bound.cc b/ui/gfx/selection_bound.cc
index 4e34107..20e6841 100644
--- a/ui/gfx/selection_bound.cc
+++ b/ui/gfx/selection_bound.cc
@@ -1,10 +1,9 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <algorithm>
-#include "base/macros.h"
#include "base/strings/stringprintf.h"
#include "ui/gfx/geometry/point_conversions.h"
#include "ui/gfx/geometry/rect.h"
diff --git a/ui/gfx/selection_bound.h b/ui/gfx/selection_bound.h
index 150b3a0..55dd611 100644
--- a/ui/gfx/selection_bound.h
+++ b/ui/gfx/selection_bound.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -78,6 +78,12 @@
GFX_EXPORT gfx::RectF RectFBetweenVisibleSelectionBounds(
const SelectionBound& b1,
const SelectionBound& b2);
-} // namespace ui
+
+// This is declared here for use in gtest-based unit tests but is defined in
+// the //ui/gfx:test_support target. Depend on that to use this in your unit
+// test. This should not be used in production code - call ToString() instead.
+void PrintTo(const SelectionBound& bound, ::std::ostream* os);
+
+} // namespace gfx
#endif // UI_GFX_SELECTION_BOUND_H_
diff --git a/ui/gfx/selection_bound_unittest.cc b/ui/gfx/selection_bound_unittest.cc
index 224ebe3..67a15fa 100644
--- a/ui/gfx/selection_bound_unittest.cc
+++ b/ui/gfx/selection_bound_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/selection_model.cc b/ui/gfx/selection_model.cc
index a792731..32ba73d 100644
--- a/ui/gfx/selection_model.cc
+++ b/ui/gfx/selection_model.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -66,7 +66,7 @@
for (auto selection : secondary_selections()) {
str += ",";
if (selection.is_empty())
- base::StringAppendF(&str, "%" PRIu32, selection.end());
+ base::StringAppendF(&str, "%" PRIuS, selection.end());
else
str += selection.ToString();
}
diff --git a/ui/gfx/selection_model.h b/ui/gfx/selection_model.h
index 150b38c..7899cd1 100644
--- a/ui/gfx/selection_model.h
+++ b/ui/gfx/selection_model.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/selection_model_unittest.cc b/ui/gfx/selection_model_unittest.cc
index 2147b2d..3b4e065 100644
--- a/ui/gfx/selection_model_unittest.cc
+++ b/ui/gfx/selection_model_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/sequential_id_generator.cc b/ui/gfx/sequential_id_generator.cc
index d8e7efb..faf4379 100644
--- a/ui/gfx/sequential_id_generator.cc
+++ b/ui/gfx/sequential_id_generator.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/sequential_id_generator.h b/ui/gfx/sequential_id_generator.h
index bc24e2c..9feb8f7 100644
--- a/ui/gfx/sequential_id_generator.h
+++ b/ui/gfx/sequential_id_generator.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,7 +10,6 @@
#include <map>
#include <unordered_map>
-#include "base/macros.h"
#include "ui/gfx/gfx_export.h"
namespace ui {
diff --git a/ui/gfx/sequential_id_generator_unittest.cc b/ui/gfx/sequential_id_generator_unittest.cc
index f36aa98..761f1fc 100644
--- a/ui/gfx/sequential_id_generator_unittest.cc
+++ b/ui/gfx/sequential_id_generator_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/shadow_util.cc b/ui/gfx/shadow_util.cc
index 04b7762..d77e035 100644
--- a/ui/gfx/shadow_util.cc
+++ b/ui/gfx/shadow_util.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -86,7 +86,9 @@
ShadowDetails::ShadowDetails(const ShadowDetails& other) = default;
ShadowDetails::~ShadowDetails() {}
-const ShadowDetails& ShadowDetails::Get(int elevation, int corner_radius) {
+const ShadowDetails& ShadowDetails::Get(int elevation,
+ int corner_radius,
+ ShadowStyle style) {
auto iter =
g_shadow_cache.Get().find(std::make_pair(elevation, corner_radius));
if (iter != g_shadow_cache.Get().end())
@@ -96,7 +98,21 @@
std::make_pair(elevation, corner_radius), ShadowDetails());
DCHECK(insertion.second);
ShadowDetails* shadow = &insertion.first->second;
- shadow->values = ShadowValue::MakeMdShadowValues(elevation);
+
+ // Generate shadow values according to the give shadow style.
+ switch (style) {
+ case ShadowStyle::kMaterialDesign:
+ shadow->values = ShadowValue::MakeMdShadowValues(elevation);
+ break;
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ case ShadowStyle::kChromeOSSystemUI:
+ shadow->values = ShadowValue::MakeChromeOSSystemUIShadowValues(elevation);
+ break;
+#endif
+ default:
+ NOTREACHED() << "Unknown shadow style.";
+ }
+
auto* source = new ShadowNineboxSource(shadow->values, corner_radius);
shadow->ninebox_image = ImageSkia(base::WrapUnique(source), source->size());
return *shadow;
diff --git a/ui/gfx/shadow_util.h b/ui/gfx/shadow_util.h
index 8f8759d..89fd2c0 100644
--- a/ui/gfx/shadow_util.h
+++ b/ui/gfx/shadow_util.h
@@ -1,16 +1,27 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_SHADOW_UTIL_H_
#define UI_GFX_SHADOW_UTIL_H_
+#include "build/chromeos_buildflags.h"
#include "ui/gfx/gfx_export.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/shadow_value.h"
namespace gfx {
+// The shadow style for different UI components.
+enum class ShadowStyle {
+ // The MD style is mainly used for view's shadow.
+ kMaterialDesign,
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // The system style is mainly used for Chrome OS UI components.
+ kChromeOSSystemUI,
+#endif
+};
+
// A struct that describes a vector of shadows and their depiction as an image
// suitable for ninebox tiling.
struct GFX_EXPORT ShadowDetails {
@@ -18,9 +29,12 @@
ShadowDetails(const ShadowDetails& other);
~ShadowDetails();
- // Returns a cached ShadowDetails for the given elevation (which controls
- // style) and corner radius. Creates the ShadowDetails first if necessary.
- static const ShadowDetails& Get(int elevation, int radius);
+ // Returns a cached ShadowDetails for the given elevation, corner radius, and
+ // shadow style. Creates the ShadowDetails first if necessary.
+ static const ShadowDetails& Get(
+ int elevation,
+ int radius,
+ ShadowStyle style = ShadowStyle::kMaterialDesign);
// Description of the shadows.
gfx::ShadowValues values;
diff --git a/ui/gfx/shadow_value.cc b/ui/gfx/shadow_value.cc
index d71ecfd..94b2426 100644
--- a/ui/gfx/shadow_value.cc
+++ b/ui/gfx/shadow_value.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -39,7 +39,7 @@
bottom = std::max(bottom, blur_length + shadow.y());
}
- return Insets(top, left, bottom, right);
+ return Insets::TLBR(top, left, bottom, right);
}
} // namespace
@@ -125,4 +125,28 @@
return shadow_values;
}
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+// static
+ShadowValues ShadowValue::MakeChromeOSSystemUIShadowValues(int elevation,
+ SkColor color) {
+ ShadowValues shadow_values;
+ // To match the CSS notion of blur (spread outside the bounding box) to the
+ // Skia notion of blur (spread outside and inside the bounding box), we have
+ // to double the designer-provided blur values.
+ const int kBlurCorrection = 2;
+ // "Key shadow": y offset is elevation and blur value is equal to the
+ // elevation.
+ shadow_values.emplace_back(Vector2d(0, elevation),
+ kBlurCorrection * elevation,
+ SkColorSetA(color, 0x3d));
+ // "Ambient shadow": no offset and blur matches the elevation.
+ shadow_values.emplace_back(Vector2d(), kBlurCorrection * elevation,
+ SkColorSetA(color, 0x1a));
+ // To see what this looks like for elevation 24, try this CSS:
+ // box-shadow: 0 24px 24px rgba(0, 0, 0, .24),
+ // 0 0 24px rgba(0, 0, 0, .10);
+ return shadow_values;
+}
+#endif
+
} // namespace gfx
diff --git a/ui/gfx/shadow_value.h b/ui/gfx/shadow_value.h
index fdb8175..a791f4f 100644
--- a/ui/gfx/shadow_value.h
+++ b/ui/gfx/shadow_value.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,6 +9,7 @@
#include <tuple>
#include <vector>
+#include "build/chromeos_buildflags.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/vector2d.h"
#include "ui/gfx/gfx_export.h"
@@ -67,6 +68,13 @@
static ShadowValues MakeMdShadowValues(int elevation,
SkColor color = SK_ColorBLACK);
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // Makes ShadowValues for Chrome OS UI components.
+ static ShadowValues MakeChromeOSSystemUIShadowValues(
+ int elevation,
+ SkColor color = SK_ColorBLACK);
+#endif
+
private:
gfx::Vector2d offset_;
diff --git a/ui/gfx/shadow_value_unittest.cc b/ui/gfx/shadow_value_unittest.cc
index 713b473..01d40f5 100644
--- a/ui/gfx/shadow_value_unittest.cc
+++ b/ui/gfx/shadow_value_unittest.cc
@@ -1,14 +1,14 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/gfx/shadow_value.h"
+
#include <stddef.h>
-#include "base/cxx17_backports.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/gfx/geometry/vector2d.h"
-#include "ui/gfx/shadow_value.h"
namespace gfx {
@@ -19,46 +19,50 @@
ShadowValue shadows[2];
} kTestCases[] = {
{
- Insets(), 0, {},
+ Insets(),
+ 0,
+ {},
},
{
- Insets(-2, -2, -2, -2),
+ Insets(-2),
1,
{
{gfx::Vector2d(0, 0), 4, 0},
},
},
{
- Insets(0, -1, -4, -3),
+ Insets::TLBR(0, -1, -4, -3),
1,
{
{gfx::Vector2d(1, 2), 4, 0},
},
},
{
- Insets(-4, -3, 0, -1),
+ Insets::TLBR(-4, -3, 0, -1),
1,
{
{gfx::Vector2d(-1, -2), 4, 0},
},
},
{
- Insets(0, -1, -5, -4),
+ Insets::TLBR(0, -1, -5, -4),
2,
{
- {gfx::Vector2d(1, 2), 4, 0}, {gfx::Vector2d(2, 3), 4, 0},
+ {gfx::Vector2d(1, 2), 4, 0},
+ {gfx::Vector2d(2, 3), 4, 0},
},
},
{
- Insets(-4, -3, -5, -4),
+ Insets::TLBR(-4, -3, -5, -4),
2,
{
- {gfx::Vector2d(-1, -2), 4, 0}, {gfx::Vector2d(2, 3), 4, 0},
+ {gfx::Vector2d(-1, -2), 4, 0},
+ {gfx::Vector2d(2, 3), 4, 0},
},
},
};
- for (size_t i = 0; i < base::size(kTestCases); ++i) {
+ for (size_t i = 0; i < std::size(kTestCases); ++i) {
Insets margin = ShadowValue::GetMargin(
ShadowValues(kTestCases[i].shadows,
kTestCases[i].shadows + kTestCases[i].shadow_count));
diff --git a/ui/gfx/skbitmap_operations.cc b/ui/gfx/skbitmap_operations.cc
index 9bcbd2e..6ad9154 100644
--- a/ui/gfx/skbitmap_operations.cc
+++ b/ui/gfx/skbitmap_operations.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/skbitmap_operations.h b/ui/gfx/skbitmap_operations.h
index 4e7e641..ebbd607 100644
--- a/ui/gfx/skbitmap_operations.h
+++ b/ui/gfx/skbitmap_operations.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/skbitmap_operations_unittest.cc b/ui/gfx/skbitmap_operations_unittest.cc
index a0be6ed..20e488a 100644
--- a/ui/gfx/skbitmap_operations_unittest.cc
+++ b/ui/gfx/skbitmap_operations_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/skia_color_space_util.cc b/ui/gfx/skia_color_space_util.cc
index 87d372d..c7418af 100644
--- a/ui/gfx/skia_color_space_util.cc
+++ b/ui/gfx/skia_color_space_util.cc
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,7 +8,7 @@
#include <cmath>
#include <vector>
-#include "base/cxx17_backports.h"
+#include "base/check.h"
namespace gfx {
@@ -20,7 +20,7 @@
float SkTransferFnEval(const skcms_TransferFunction& fn, float x) {
float fn_at_x_unclamped = SkTransferFnEvalUnclamped(fn, x);
- return base::clamp(fn_at_x_unclamped, 0.0f, 1.0f);
+ return std::clamp(fn_at_x_unclamped, 0.0f, 1.0f);
}
skcms_TransferFunction SkTransferFnInverse(const skcms_TransferFunction& fn) {
@@ -80,17 +80,29 @@
return true;
}
-bool SkMatrixIsApproximatelyIdentity(const skia::Matrix44& m) {
+#if !defined(STARBOARD)
+bool SkM44IsApproximatelyIdentity(const SkM44& m) {
const float kEpsilon = 1.f / 256.f;
for (int i = 0; i < 4; ++i) {
for (int j = 0; j < 4; ++j) {
float identity_value = i == j ? 1 : 0;
- float value = m.get(i, j);
+ float value = m.rc(i, j);
if (std::abs(identity_value - value) > kEpsilon)
return false;
}
}
return true;
}
+#endif // !defined(STARBOARD)
+
+SkM44 SkM44FromRowMajor3x3(const float* data) {
+ DCHECK(data);
+ // clang-format off
+ return SkM44(data[0], data[1], data[2], 0,
+ data[3], data[4], data[5], 0,
+ data[6], data[7], data[8], 0,
+ 0, 0, 0, 1);
+ // clang-format on
+}
} // namespace gfx
diff --git a/ui/gfx/skia_color_space_util.h b/ui/gfx/skia_color_space_util.h
index 0048eba..32875fd 100644
--- a/ui/gfx/skia_color_space_util.h
+++ b/ui/gfx/skia_color_space_util.h
@@ -1,13 +1,17 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_SKIA_COLOR_SPACE_UTIL_H_
#define UI_GFX_SKIA_COLOR_SPACE_UTIL_H_
-#include "skia/ext/skia_matrix_44.h"
#include "third_party/skia/include/core/SkColorSpace.h"
-#include "third_party/skia/include/core/SkICC.h"
+#include "third_party/skia/include/core/SkM44.h"
+#if defined(STARBOARD)
+#include "third_party/skia/include/third_party/skcms/skcms.h"
+#else // defined(STARBOARD)
+#include "third_party/skia/modules/skcms/skcms.h"
+#endif // defined(STARBOARD)
#include "ui/gfx/color_space_export.h"
namespace gfx {
@@ -35,8 +39,11 @@
bool COLOR_SPACE_EXPORT
SkTransferFnIsApproximatelyIdentity(const skcms_TransferFunction& fn);
-bool COLOR_SPACE_EXPORT
-SkMatrixIsApproximatelyIdentity(const skia::Matrix44& m);
+#if !defined(STARBOARD)
+bool COLOR_SPACE_EXPORT SkM44IsApproximatelyIdentity(const SkM44& m);
+#endif // !defined(STARBOARD)
+
+SkM44 COLOR_SPACE_EXPORT SkM44FromRowMajor3x3(const float* scale);
} // namespace gfx
diff --git a/ui/gfx/skia_font_delegate.cc b/ui/gfx/skia_font_delegate.cc
deleted file mode 100644
index f7c24c5..0000000
--- a/ui/gfx/skia_font_delegate.cc
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/skia_font_delegate.h"
-
-namespace {
-
-gfx::SkiaFontDelegate* g_skia_font_delegate = 0;
-
-} // namespace
-
-namespace gfx {
-
-void SkiaFontDelegate::SetInstance(SkiaFontDelegate* instance) {
- g_skia_font_delegate = instance;
-}
-
-const SkiaFontDelegate* SkiaFontDelegate::instance() {
- return g_skia_font_delegate;
-}
-
-} // namespace gfx
diff --git a/ui/gfx/skia_font_delegate.h b/ui/gfx/skia_font_delegate.h
deleted file mode 100644
index 05636e9..0000000
--- a/ui/gfx/skia_font_delegate.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_SKIA_FONT_DELEGATE_H_
-#define UI_GFX_SKIA_FONT_DELEGATE_H_
-
-#include <memory>
-#include <string>
-
-#include "ui/gfx/font_render_params.h"
-#include "ui/gfx/gfx_export.h"
-
-namespace gfx {
-
-// Allows a Linux platform-specific overriding of font preferences.
-class GFX_EXPORT SkiaFontDelegate {
- public:
- virtual ~SkiaFontDelegate() {}
-
- // Sets the dynamically loaded singleton that provides font preferences.
- // This pointer is not owned, and if this method is called a second time,
- // the first instance is not deleted.
- static void SetInstance(SkiaFontDelegate* instance);
-
- // Returns a SkiaFontDelegate instance for the toolkit used in
- // the user's desktop environment.
- //
- // Can return NULL, in case no toolkit has been set. (For example, if we're
- // running with the "--ash" flag.)
- static const SkiaFontDelegate* instance();
-
- // Returns the default font rendering settings.
- virtual FontRenderParams GetDefaultFontRenderParams() const = 0;
-
- // Returns details about the default UI font. |style_out| holds a bitfield of
- // gfx::Font::Style values.
- virtual void GetDefaultFontDescription(
- std::string* family_out,
- int* size_pixels_out,
- int* style_out,
- Font::Weight* weight_out,
- FontRenderParams* params_out) const = 0;
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_SKIA_FONT_DELEGATE_H_
diff --git a/ui/gfx/skia_paint_util.cc b/ui/gfx/skia_paint_util.cc
index 7bc2d44..df0cc56 100644
--- a/ui/gfx/skia_paint_util.cc
+++ b/ui/gfx/skia_paint_util.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -61,7 +61,9 @@
const gfx::Point& end_point,
SkColor start_color,
SkColor end_color) {
- SkColor grad_colors[2] = {start_color, end_color};
+ // TODO(crbug/1308932): Remove FromColor and make all SkColor4f.
+ SkColor4f grad_colors[2] = {SkColor4f::FromColor(start_color),
+ SkColor4f::FromColor(end_color)};
SkPoint grad_points[2] = {gfx::PointToSkPoint(start_point),
gfx::PointToSkPoint(end_point)};
diff --git a/ui/gfx/skia_paint_util.h b/ui/gfx/skia_paint_util.h
index 7a00067..ffba50e 100644
--- a/ui/gfx/skia_paint_util.h
+++ b/ui/gfx/skia_paint_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/skia_util.cc b/ui/gfx/skia_util.cc
index 9df544a..73b55a7 100644
--- a/ui/gfx/skia_util.cc
+++ b/ui/gfx/skia_util.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/skia_util.h b/ui/gfx/skia_util.h
index fb5f20d..ef11e57 100644
--- a/ui/gfx/skia_util.h
+++ b/ui/gfx/skia_util.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/skia_util_unittest.cc b/ui/gfx/skia_util_unittest.cc
index 34ce126..91f86fe 100644
--- a/ui/gfx/skia_util_unittest.cc
+++ b/ui/gfx/skia_util_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/skrect_conversion_unittest.cc b/ui/gfx/skrect_conversion_unittest.cc
deleted file mode 100644
index 2725e04..0000000
--- a/ui/gfx/skrect_conversion_unittest.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/skia_conversions.h"
-
-namespace gfx {
-
-TEST(RectTest, SkiaRectConversions) {
- Rect isrc(10, 20, 30, 40);
- RectF fsrc(10.5f, 20.5f, 30.5f, 40.5f);
-
- SkIRect skirect = RectToSkIRect(isrc);
- EXPECT_EQ(isrc.ToString(), SkIRectToRect(skirect).ToString());
-
- SkRect skrect = RectToSkRect(isrc);
- EXPECT_EQ(gfx::RectF(isrc).ToString(), SkRectToRectF(skrect).ToString());
-
- skrect = RectFToSkRect(fsrc);
- EXPECT_EQ(fsrc.ToString(), SkRectToRectF(skrect).ToString());
-}
-
-TEST(RectTest, SkIRectToRectClamping) {
- // This clamping only makes sense if SkIRect and gfx::Rect have the same size.
- // Otherwise, either other overflows can occur that we don't handle, or no
- // overflows can ocur.
- if (sizeof(int) != sizeof(int32_t))
- return;
- using Limits = std::numeric_limits<int>;
-
- // right-left and bottom-top would overflow.
- // These should be mapped to max width/height, which is as close as gfx::Rect
- // can represent.
- Rect result = SkIRectToRect(SkIRect::MakeLTRB(Limits::min(), Limits::min(),
- Limits::max(), Limits::max()));
- EXPECT_EQ(gfx::Size(Limits::max(), Limits::max()), result.size());
-
- // right-left and bottom-top would underflow.
- // These should be mapped to zero, like all negative values.
- result = SkIRectToRect(SkIRect::MakeLTRB(Limits::max(), Limits::max(),
- Limits::min(), Limits::min()));
- EXPECT_EQ(gfx::Rect(Limits::max(), Limits::max(), 0, 0), result);
-}
-
-} // namespace gfx
diff --git a/ui/gfx/surface_origin.h b/ui/gfx/surface_origin.h
index 0f51513..837793c 100644
--- a/ui/gfx/surface_origin.h
+++ b/ui/gfx/surface_origin.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/swap_result.cc b/ui/gfx/swap_result.cc
index 9d600c7..9d4f319 100644
--- a/ui/gfx/swap_result.cc
+++ b/ui/gfx/swap_result.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/swap_result.h b/ui/gfx/swap_result.h
index 39a62d5..dd407ce 100644
--- a/ui/gfx/swap_result.h
+++ b/ui/gfx/swap_result.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -41,15 +41,13 @@
// dicontinuities in associated UMA data.
base::TimeTicks swap_end;
- // When Display Compositor thread scheduled work to GPU Thread. For GLRenderer
- // it's when InProcessCommandBuffer::Flush() happens, for SkiaRenderer it's
- // PostTask time for FinishPaintRenderPass or SwapBuffers whichever comes
- // first.
+ // When Display Compositor thread scheduled work to GPU Thread. For
+ // SkiaRenderer it's PostTask time for FinishPaintRenderPass or SwapBuffers
+ // whichever comes first.
base::TimeTicks viz_scheduled_draw;
// When GPU thread started draw submitted by Display Compositor thread. For
- // GLRenderer it's InProcessCommandBuffer::FlushOnGpuThread, for SkiaRenderer
- // it's FinishPaintRenderPass/SwapBuffers.
+ // SkiaRenderer it's FinishPaintRenderPass/SwapBuffers.
base::TimeTicks gpu_started_draw;
// When GPU scheduler removed the last required dependency.
diff --git a/ui/gfx/switches.cc b/ui/gfx/switches.cc
index 6733cbe..cbdfb60 100644
--- a/ui/gfx/switches.cc
+++ b/ui/gfx/switches.cc
@@ -1,10 +1,12 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "build/build_config.h"
#include "ui/gfx/switches.h"
+#include "base/command_line.h"
+#include "build/build_config.h"
+
namespace switches {
// Scale factor to apply to every animation duration. Must be >= 0.0. This will
@@ -16,6 +18,11 @@
const char kDisableFontSubpixelPositioning[] =
"disable-font-subpixel-positioning";
+// Disables new code to run SharedImages for NaCL swapchain. This overrides
+// value of kPPAPISharedImagesSwapChain feature flag.
+const char kDisablePPAPISharedImagesSwapChain[] =
+ "disable-ppapi-shared-images-swapchain";
+
// Enable native CPU-mappable GPU memory buffer support on Linux.
const char kEnableNativeGpuMemoryBuffers[] = "enable-native-gpu-memory-buffers";
@@ -26,17 +33,47 @@
// Run in headless mode, i.e., without a UI or display server dependencies.
const char kHeadless[] = "headless";
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+// Which X11 display to connect to. Emulates the GTK+ "--display=" command line
+// argument. In use only with Ozone/X11.
+const char kX11Display[] = "display";
+// Disables MIT-SHM extension. In use only with Ozone/X11.
+const char kNoXshm[] = "no-xshm";
+#endif
+
} // namespace switches
namespace features {
-
-const base::Feature kOddHeightMultiPlanarBuffers {
- "OddHeightMultiPlanarBuffers",
-#if defined(OS_MAC)
- base::FEATURE_ENABLED_BY_DEFAULT
+BASE_FEATURE(kOddHeightMultiPlanarBuffers,
+ "OddHeightMultiPlanarBuffers",
+#if BUILDFLAG(IS_APPLE)
+ base::FEATURE_ENABLED_BY_DEFAULT
#else
- base::FEATURE_DISABLED_BY_DEFAULT
+ base::FEATURE_DISABLED_BY_DEFAULT
#endif
-};
+);
+
+BASE_FEATURE(kOddWidthMultiPlanarBuffers,
+ "OddWidthMultiPlanarBuffers",
+#if BUILDFLAG(IS_APPLE)
+ base::FEATURE_ENABLED_BY_DEFAULT
+#else
+ base::FEATURE_DISABLED_BY_DEFAULT
+#endif
+);
+
+BASE_FEATURE(kPPAPISharedImagesSwapChain,
+ "PPAPISharedImagesSwapChain",
+ base::FEATURE_ENABLED_BY_DEFAULT);
+
+#if BUILDFLAG(IS_CHROMEOS)
+BASE_FEATURE(kVariableGoogleSansFont,
+ "VariableGoogleSansFont",
+ base::FEATURE_DISABLED_BY_DEFAULT);
+
+GFX_SWITCHES_EXPORT bool UseVariableGoogleSansFont() {
+ return base::FeatureList::IsEnabled(kVariableGoogleSansFont);
+}
+#endif
} // namespace features
diff --git a/ui/gfx/switches.h b/ui/gfx/switches.h
index afb36f3..df35209 100644
--- a/ui/gfx/switches.h
+++ b/ui/gfx/switches.h
@@ -1,4 +1,4 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,19 +7,36 @@
#include "base/feature_list.h"
#include "build/build_config.h"
+#include "build/chromeos_buildflags.h"
#include "ui/gfx/switches_export.h"
namespace switches {
GFX_SWITCHES_EXPORT extern const char kAnimationDurationScale[];
GFX_SWITCHES_EXPORT extern const char kDisableFontSubpixelPositioning[];
+GFX_SWITCHES_EXPORT extern const char kDisablePPAPISharedImagesSwapChain[];
GFX_SWITCHES_EXPORT extern const char kEnableNativeGpuMemoryBuffers[];
GFX_SWITCHES_EXPORT extern const char kForcePrefersReducedMotion[];
GFX_SWITCHES_EXPORT extern const char kHeadless[];
+
+#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
+GFX_SWITCHES_EXPORT extern const char kX11Display[];
+GFX_SWITCHES_EXPORT extern const char kNoXshm[];
+#endif
+
} // namespace switches
namespace features {
-GFX_SWITCHES_EXPORT extern const base::Feature kOddHeightMultiPlanarBuffers;
+
+GFX_SWITCHES_EXPORT BASE_DECLARE_FEATURE(kOddHeightMultiPlanarBuffers);
+GFX_SWITCHES_EXPORT BASE_DECLARE_FEATURE(kOddWidthMultiPlanarBuffers);
+GFX_SWITCHES_EXPORT BASE_DECLARE_FEATURE(kPPAPISharedImagesSwapChain);
+
+#if BUILDFLAG(IS_CHROMEOS)
+GFX_SWITCHES_EXPORT BASE_DECLARE_FEATURE(kVariableGoogleSansFont);
+GFX_SWITCHES_EXPORT bool UseVariableGoogleSansFont();
+#endif
+
} // namespace features
#endif // UI_GFX_SWITCHES_H_
diff --git a/ui/gfx/switches_export.h b/ui/gfx/switches_export.h
index 34418ae..ba153f2 100644
--- a/ui/gfx/switches_export.h
+++ b/ui/gfx/switches_export.h
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/sys_color_change_listener.cc b/ui/gfx/sys_color_change_listener.cc
index 72dae9f..d1313a5 100644
--- a/ui/gfx/sys_color_change_listener.cc
+++ b/ui/gfx/sys_color_change_listener.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,8 +8,8 @@
#include <memory>
-#include "base/bind.h"
-#include "base/callback_helpers.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_helpers.h"
#include "base/memory/singleton.h"
#include "base/observer_list.h"
#include "ui/gfx/win/singleton_hwnd_observer.h"
diff --git a/ui/gfx/sys_color_change_listener.h b/ui/gfx/sys_color_change_listener.h
index 4dbbe9d..87c8d4e 100644
--- a/ui/gfx/sys_color_change_listener.h
+++ b/ui/gfx/sys_color_change_listener.h
@@ -1,11 +1,11 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_SYS_COLOR_CHANGE_LISTENER_H_
#define UI_GFX_SYS_COLOR_CHANGE_LISTENER_H_
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
#include "ui/gfx/gfx_export.h"
namespace gfx {
@@ -32,7 +32,7 @@
~ScopedSysColorChangeListener();
private:
- SysColorChangeListener* listener_;
+ raw_ptr<SysColorChangeListener> listener_;
};
} // namespace gfx;
diff --git a/ui/gfx/system_fonts_win.cc b/ui/gfx/system_fonts_win.cc
index 0ed4445..4fa322e 100644
--- a/ui/gfx/system_fonts_win.cc
+++ b/ui/gfx/system_fonts_win.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -268,22 +268,6 @@
return SystemFonts::Instance()->GetFont(system_font);
}
-NativeFont AdjustExistingSystemFont(NativeFont existing_font,
- const FontAdjustment& font_adjustment) {
- LOGFONT logfont;
- auto result = GetObject(existing_font, sizeof(logfont), &logfont);
- DCHECK(result);
-
- // Make the necessary adjustments.
- SystemFonts::AdjustLOGFONT(font_adjustment, &logfont);
-
- // Cap at minimum font size.
- logfont.lfHeight = SystemFonts::AdjustFontSize(logfont.lfHeight, 0);
-
- // Create the Font object.
- return ::CreateFontIndirect(&logfont);
-}
-
int AdjustFontSize(int lf_height, int size_delta) {
return SystemFonts::AdjustFontSize(lf_height, size_delta);
}
diff --git a/ui/gfx/system_fonts_win.h b/ui/gfx/system_fonts_win.h
index acf63cd..5120a9d 100644
--- a/ui/gfx/system_fonts_win.h
+++ b/ui/gfx/system_fonts_win.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -42,11 +42,6 @@
// elements.
GFX_EXPORT const Font& GetSystemFont(SystemFont system_font);
-// Applies a font adjustment to an existing native font.
-GFX_EXPORT NativeFont
-AdjustExistingSystemFont(NativeFont existing_font,
- const FontAdjustment& font_adjustment);
-
// Computes and returns the adjusted size of a font, subject to the global
// minimum size. |lf_height| is the height as reported by the LOGFONT structure,
// and may be positive or negative (but is typically negative, indicating
diff --git a/ui/gfx/system_fonts_win_unittest.cc b/ui/gfx/system_fonts_win_unittest.cc
index 9e736b9..e48d54c 100644
--- a/ui/gfx/system_fonts_win_unittest.cc
+++ b/ui/gfx/system_fonts_win_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -24,7 +24,7 @@
protected:
void SetUp() override {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// System fonts is keeping a cache of loaded system fonts. These fonts are
// scaled based on global callbacks configured on startup. The tests in this
// file are testing these callbacks and need to be sure we cleared the
diff --git a/ui/gfx/test/OWNERS b/ui/gfx/test/OWNERS
index 8b2fc78..50dca81 100644
--- a/ui/gfx/test/OWNERS
+++ b/ui/gfx/test/OWNERS
@@ -1,3 +1,6 @@
# Fonts and fallback fonts.
per-file font*=etienneb@chromium.org
per-file font*=robliao@chromium.org
+
+# Anyone can update test bundle data filelists.
+per-file *.filelist=*
diff --git a/ui/gfx/test/data/render_text/unicode_text_fuzzer.dict b/ui/gfx/test/data/render_text/unicode_text_fuzzer.dict
index 59f7bd6..1658b21 100644
--- a/ui/gfx/test/data/render_text/unicode_text_fuzzer.dict
+++ b/ui/gfx/test/data/render_text/unicode_text_fuzzer.dict
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# Copyright 2019 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/ui/gfx/test/data/unit_tests_bundle_data.filelist b/ui/gfx/test/data/unit_tests_bundle_data.filelist
new file mode 100644
index 0000000..9c71ae2
--- /dev/null
+++ b/ui/gfx/test/data/unit_tests_bundle_data.filelist
@@ -0,0 +1,12 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# NOTE: this file is generated by build/ios/update_bundle_filelist.py
+# If it requires updating, you should get a presubmit error with
+# instructions on how to regenerate. Otherwise, do not edit.
+//ui/gfx/test/data/compositor/BackgroundBlur1.png
+//ui/gfx/test/data/compositor/BackgroundBlur1_zoom.png
+//ui/gfx/test/data/compositor/BackgroundBlur2.png
+//ui/gfx/test/data/compositor/ModifyHierarchy1.png
+//ui/gfx/test/data/compositor/ModifyHierarchy2.png
+//ui/gfx/test/data/compositor/Opacity.png
diff --git a/ui/gfx/test/data/unit_tests_bundle_data.globlist b/ui/gfx/test/data/unit_tests_bundle_data.globlist
new file mode 100644
index 0000000..7d4633b
--- /dev/null
+++ b/ui/gfx/test/data/unit_tests_bundle_data.globlist
@@ -0,0 +1,10 @@
+# Copyright 2023 The Chromium Authors
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+# NOTE: this file is generated by build/ios/update_bundle_filelist.py
+# If it requires updating, you should get a presubmit error with
+# instructions on how to regenerate. Otherwise, do not edit.
+
+//ui/gfx/test/data/compositor/**
+-//ui/gfx/test/data/compositor/**.filelist
+-//ui/gfx/test/data/compositor/**.globlist
diff --git a/ui/gfx/test/font_fallback_test_data.cc b/ui/gfx/test/font_fallback_test_data.cc
index a95fafe..1087cd1 100644
--- a/ui/gfx/test/font_fallback_test_data.cc
+++ b/ui/gfx/test/font_fallback_test_data.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,10 +10,6 @@
namespace gfx {
-#if defined(OS_WIN)
-constexpr bool kWin10Only = true;
-#endif
-
FallbackFontTestCase::FallbackFontTestCase() = default;
FallbackFontTestCase::FallbackFontTestCase(const FallbackFontTestCase& other) =
default;
@@ -22,24 +18,22 @@
UScriptCode script_arg,
std::string language_tag_arg,
std::u16string text_arg,
- std::vector<std::string> fallback_fonts_arg,
- bool is_win10_arg)
+ std::vector<std::string> fallback_fonts_arg)
: script(script_arg),
language_tag(language_tag_arg),
text(text_arg),
- fallback_fonts(fallback_fonts_arg),
- is_win10(is_win10_arg) {}
+ fallback_fonts(fallback_fonts_arg) {}
FallbackFontTestCase::~FallbackFontTestCase() = default;
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// A list of script and the fallback font on a default windows installation.
// This list may need to be updated if fonts or operating systems are
// upgraded.
// TODO(drott): Some of the test cases lack a valid language tag as it's unclear
// which language in particular would be expressed with the respective ancient
// script. Ideally we'd find a meaningful language tag for those.
-std::vector<FallbackFontTestCase> kGetFontFallbackTests = {
+const std::vector<FallbackFontTestCase> kGetFontFallbackTests = {
{USCRIPT_ARABIC,
"ar",
u"\u062A\u062D",
@@ -50,55 +44,31 @@
{"Segoe UI", "Tahoma", "Sylfaen", "Times New Roman"}},
{USCRIPT_BENGALI, "bn", u"\u09B8\u09AE", {"Nirmala UI", "Vrinda"}},
{USCRIPT_BRAILLE, "en-us-brai", u"\u2870\u2871", {"Segoe UI Symbol"}},
- {USCRIPT_BUGINESE, "bug", u"\u1A00\u1A01", {"Leelawadee UI"}, kWin10Only},
+ {USCRIPT_BUGINESE, "bug", u"\u1A00\u1A01", {"Leelawadee UI"}},
{USCRIPT_CANADIAN_ABORIGINAL,
"cans",
u"\u1410\u1411",
{"Gadugi", "Euphemia"}},
- {USCRIPT_CARIAN,
- "xcr",
- u"\U000102A0\U000102A1",
- {"Segoe UI Historic"},
- kWin10Only},
+ {USCRIPT_CARIAN, "xcr", u"\U000102A0\U000102A1", {"Segoe UI Historic"}},
{USCRIPT_CHEROKEE,
"chr",
u"\u13A1\u13A2",
{"Gadugi", "Plantagenet Cherokee"}},
- {USCRIPT_COPTIC,
- "copt",
- u"\u2C81\u2C82",
- {"Segoe UI Historic"},
- kWin10Only},
+ {USCRIPT_COPTIC, "copt", u"\u2C81\u2C82", {"Segoe UI Historic"}},
- {USCRIPT_CUNEIFORM,
- "akk",
- u"\U00012000\U0001200C",
- {"Segoe UI Historic"},
- kWin10Only},
+ {USCRIPT_CUNEIFORM, "akk", u"\U00012000\U0001200C", {"Segoe UI Historic"}},
- {USCRIPT_CYPRIOT,
- "ecy",
- u"\U00010800\U00010801",
- {"Segoe UI Historic"},
- kWin10Only},
+ {USCRIPT_CYPRIOT, "ecy", u"\U00010800\U00010801", {"Segoe UI Historic"}},
{USCRIPT_CYRILLIC, "ru", u"\u0410\u0411\u0412", {"Times New Roman"}},
- {USCRIPT_DESERET,
- "en",
- u"\U00010400\U00010401",
- {"Segoe UI Symbol"},
- kWin10Only},
+ {USCRIPT_DESERET, "en", u"\U00010400\U00010401", {"Segoe UI Symbol"}},
{USCRIPT_ETHIOPIC, "am", u"\u1201\u1202", {"Ebrima", "Nyala"}},
- {USCRIPT_GEORGIAN,
- "ka",
- u"\u10A0\u10A1",
- {"Sylfaen", "Segoe UI"},
- kWin10Only},
+ {USCRIPT_GEORGIAN, "ka", u"\u10A0\u10A1", {"Sylfaen", "Segoe UI"}},
{USCRIPT_GREEK, "el", u"\u0391\u0392", {"Times New Roman"}},
{USCRIPT_GURMUKHI, "pa", u"\u0A21\u0A22", {"Raavi", "Nirmala UI"}},
{USCRIPT_HAN,
@@ -118,11 +88,7 @@
u"\u6211",
{"Microsoft JhengHei", "Microsoft JhengHei UI"}},
{USCRIPT_HAN, "ja", u"\u6211", {"Meiryo UI", "Yu Gothic UI", "Yu Gothic"}},
- {USCRIPT_HANGUL,
- "ko",
- u"\u1100\u1101",
- {"Malgun Gothic", "Gulim"},
- kWin10Only},
+ {USCRIPT_HANGUL, "ko", u"\u1100\u1101", {"Malgun Gothic", "Gulim"}},
{USCRIPT_HEBREW,
"he",
u"\u05D1\u05D2",
@@ -135,57 +101,39 @@
{USCRIPT_IMPERIAL_ARAMAIC,
"arc",
u"\U00010841\U00010842",
- {"Segoe UI Historic"},
- kWin10Only},
+ {"Segoe UI Historic"}},
{USCRIPT_INSCRIPTIONAL_PAHLAVI,
"pal",
u"\U00010B61\U00010B62",
- {"Segoe UI Historic"},
- kWin10Only},
+ {"Segoe UI Historic"}},
{USCRIPT_INSCRIPTIONAL_PARTHIAN,
"xpr",
u"\U00010B41\U00010B42",
- {"Segoe UI Historic"},
- kWin10Only},
+ {"Segoe UI Historic"}},
- {USCRIPT_JAVANESE, "jv", u"\uA991\uA992", {"Javanese Text"}, kWin10Only},
- {USCRIPT_KANNADA, "kn", u"\u0CA1\u0CA2", {"Nirmala UI", "Tunga"}},
-
- {USCRIPT_KHAROSHTHI,
- "sa",
- u"\U00010A10\U00010A11",
- {"Segoe UI Historic"},
- kWin10Only},
+ {USCRIPT_JAVANESE, "jv", u"\uA991\uA992", {"Javanese Text"}},
+ {USCRIPT_KHAROSHTHI, "sa", u"\U00010A10\U00010A11", {"Segoe UI Historic"}},
{USCRIPT_LAO,
"lo",
u"\u0ED0\u0ED1",
{"Lao UI", "Leelawadee UI", "Segoe UI"}},
- {USCRIPT_LISU, "lis", u"\uA4D0\uA4D1", {"Segoe UI"}, kWin10Only},
+ {USCRIPT_LISU, "lis", u"\uA4D0\uA4D1", {"Segoe UI"}},
- {USCRIPT_LYCIAN,
- "xlc",
- u"\U00010281\U00010282",
- {"Segoe UI Historic"},
- kWin10Only},
+ {USCRIPT_LYCIAN, "xlc", u"\U00010281\U00010282", {"Segoe UI Historic"}},
- {USCRIPT_LYDIAN,
- "xld",
- u"\U00010921\U00010922",
- {"Segoe UI Historic"},
- kWin10Only},
+ {USCRIPT_LYDIAN, "xld", u"\U00010921\U00010922", {"Segoe UI Historic"}},
{USCRIPT_MALAYALAM, "ml", u"\u0D21\u0D22", {"Kartika", "Nirmala UI"}},
{USCRIPT_MEROITIC_CURSIVE,
"",
u"\U000109A1\U000109A2",
- {"Segoe UI Historic"},
- kWin10Only},
+ {"Segoe UI Historic"}},
- {USCRIPT_MYANMAR, "my", u"\u1000\u1001", {"Myanmar Text"}, kWin10Only},
+ {USCRIPT_MYANMAR, "my", u"\u1000\u1001", {"Myanmar Text"}},
{USCRIPT_NEW_TAI_LUE, "", u"\u1981\u1982", {"Microsoft New Tai Lue"}},
{USCRIPT_NKO, "nko", u"\u07C1\u07C2", {"Ebrima", "Segoe UI"}},
@@ -194,7 +142,7 @@
u"\u1680\u1681",
{"Segoe UI Symbol", "Segoe UI Historic"}},
- {USCRIPT_OL_CHIKI, "", u"\u1C51\u1C52", {"Nirmala UI"}, kWin10Only},
+ {USCRIPT_OL_CHIKI, "", u"\u1C51\u1C52", {"Nirmala UI"}},
{USCRIPT_OLD_ITALIC,
"",
@@ -204,14 +152,12 @@
{USCRIPT_OLD_PERSIAN,
"peo",
u"\U000103A1\U000103A2",
- {"Segoe UI Historic"},
- kWin10Only},
+ {"Segoe UI Historic"}},
{USCRIPT_OLD_SOUTH_ARABIAN,
"",
u"\U00010A61\U00010A62",
- {"Segoe UI Historic"},
- kWin10Only},
+ {"Segoe UI Historic"}},
{USCRIPT_ORIYA, "or", u"\u0B21\u0B22", {"Kalinga", "Nirmala UI"}},
{USCRIPT_PHAGS_PA, "", u"\uA841\uA842", {"Microsoft PhagsPa"}},
@@ -224,16 +170,11 @@
{USCRIPT_SHAVIAN,
"",
u"\U00010451\U00010452",
- {"Segoe UI", "Segoe UI Historic"},
- kWin10Only},
+ {"Segoe UI", "Segoe UI Historic"}},
{USCRIPT_SINHALA, "si", u"\u0D91\u0D92", {"Iskoola Pota", "Nirmala UI"}},
- {USCRIPT_SORA_SOMPENG,
- "",
- u"\U000110D1\U000110D2",
- {"Nirmala UI"},
- kWin10Only},
+ {USCRIPT_SORA_SOMPENG, "", u"\U000110D1\U000110D2", {"Nirmala UI"}},
{USCRIPT_SYRIAC,
"syr",
@@ -247,20 +188,19 @@
{USCRIPT_THAI,
"th",
u"\u0e01\u0e02",
- {"Tahoma", "Leelawadee UI", "Leelawadee"},
- kWin10Only},
+ {"Tahoma", "Leelawadee UI", "Leelawadee"}},
{USCRIPT_TIBETAN, "bo", u"\u0F01\u0F02", {"Microsoft Himalaya"}},
{USCRIPT_TIFINAGH, "", u"\u2D31\u2D32", {"Ebrima"}},
{USCRIPT_VAI, "vai", u"\uA501\uA502", {"Ebrima"}},
{USCRIPT_YI, "yi", u"\uA000\uA001", {"Microsoft Yi Baiti"}}};
-#elif defined(OS_LINUX) || defined(OS_CHROMEOS)
+#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
// A list of script and the fallback font on the linux test environment.
// On linux, font-config configuration and fonts are mock. The config
// can be found in '${build}/etc/fonts/fonts.conf' and the test fonts
// can be found in '${build}/test_fonts/*'.
-std::vector<FallbackFontTestCase> kGetFontFallbackTests = {
+const std::vector<FallbackFontTestCase> kGetFontFallbackTests = {
{USCRIPT_BENGALI, "bn", u"\u09B8\u09AE", {"Mukti Narrow"}},
{USCRIPT_DEVANAGARI, "hi", u"\u0905\u0906", {"Lohit Devanagari"}},
{USCRIPT_GURMUKHI, "pa", u"\u0A21\u0A22", {"Lohit Gurmukhi"}},
@@ -273,7 +213,7 @@
#else
// No fallback font tests are defined on that platform.
-std::vector<FallbackFontTestCase> kGetFontFallbackTests = {};
+const std::vector<FallbackFontTestCase> kGetFontFallbackTests = {};
#endif
diff --git a/ui/gfx/test/font_fallback_test_data.h b/ui/gfx/test/font_fallback_test_data.h
index cfc89e3..24bf19f 100644
--- a/ui/gfx/test/font_fallback_test_data.h
+++ b/ui/gfx/test/font_fallback_test_data.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -18,18 +18,16 @@
FallbackFontTestCase(UScriptCode script_arg,
std::string language_tag_arg,
std::u16string text_arg,
- std::vector<std::string> fallback_fonts_arg,
- bool is_win10_arg = false);
+ std::vector<std::string> fallback_fonts_arg);
FallbackFontTestCase(const FallbackFontTestCase& other);
~FallbackFontTestCase();
UScriptCode script;
std::string language_tag;
std::u16string text;
std::vector<std::string> fallback_fonts;
- bool is_win10 = false;
};
-extern std::vector<FallbackFontTestCase> kGetFontFallbackTests;
+extern const std::vector<FallbackFontTestCase> kGetFontFallbackTests;
} // namespace gfx
diff --git a/ui/gfx/test/gfx_util.cc b/ui/gfx/test/gfx_util.cc
deleted file mode 100644
index 8037ee1..0000000
--- a/ui/gfx/test/gfx_util.cc
+++ /dev/null
@@ -1,202 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/test/gfx_util.h"
-
-#include <iomanip>
-#include <sstream>
-#include <string>
-
-#include "ui/gfx/geometry/axis_transform2d.h"
-#include "ui/gfx/geometry/box_f.h"
-#include "ui/gfx/geometry/insets.h"
-#include "ui/gfx/geometry/insets_f.h"
-#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/geometry/point3_f.h"
-#include "ui/gfx/geometry/point_f.h"
-#include "ui/gfx/geometry/quad_f.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/rect_f.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/gfx/geometry/size_f.h"
-#include "ui/gfx/geometry/transform.h"
-#include "ui/gfx/geometry/vector2d.h"
-#include "ui/gfx/geometry/vector2d_f.h"
-#include "ui/gfx/geometry/vector3d_f.h"
-
-namespace gfx {
-
-namespace {
-
-std::string ColorAsString(SkColor color) {
- std::ostringstream stream;
- stream << std::hex << std::uppercase << "#" << std::setfill('0')
- << std::setw(2) << SkColorGetA(color)
- << std::setw(2) << SkColorGetR(color)
- << std::setw(2) << SkColorGetG(color)
- << std::setw(2) << SkColorGetB(color);
- return stream.str();
-}
-
-bool FloatAlmostEqual(float a, float b) {
- // FloatLE is the gtest predicate for less than or almost equal to.
- return ::testing::FloatLE("a", "b", a, b) &&
- ::testing::FloatLE("b", "a", b, a);
-}
-
-} // namespace
-
-::testing::AssertionResult AssertAxisTransform2dFloatEqual(
- const char* lhs_expr,
- const char* rhs_expr,
- const AxisTransform2d& lhs,
- const AxisTransform2d& rhs) {
- if (FloatAlmostEqual(lhs.scale().x(), rhs.scale().x()) &&
- FloatAlmostEqual(lhs.scale().y(), rhs.scale().y()) &&
- FloatAlmostEqual(lhs.translation().x(), rhs.translation().x()) &&
- FloatAlmostEqual(lhs.translation().y(), rhs.translation().y())) {
- return ::testing::AssertionSuccess();
- }
- return ::testing::AssertionFailure()
- << "Value of: " << rhs_expr << "\n Actual: " << rhs.ToString()
- << "\nExpected: " << lhs_expr << "\nWhich is: " << lhs.ToString();
-}
-
-::testing::AssertionResult AssertBoxFloatEqual(const char* lhs_expr,
- const char* rhs_expr,
- const BoxF& lhs,
- const BoxF& rhs) {
- if (FloatAlmostEqual(lhs.x(), rhs.x()) &&
- FloatAlmostEqual(lhs.y(), rhs.y()) &&
- FloatAlmostEqual(lhs.z(), rhs.z()) &&
- FloatAlmostEqual(lhs.width(), rhs.width()) &&
- FloatAlmostEqual(lhs.height(), rhs.height()) &&
- FloatAlmostEqual(lhs.depth(), rhs.depth())) {
- return ::testing::AssertionSuccess();
- }
- return ::testing::AssertionFailure() << "Value of: " << rhs_expr
- << "\n Actual: " << rhs.ToString()
- << "\nExpected: " << lhs_expr
- << "\nWhich is: " << lhs.ToString();
-}
-
-::testing::AssertionResult AssertPointFloatEqual(const char* lhs_expr,
- const char* rhs_expr,
- const PointF& lhs,
- const PointF& rhs) {
- if (FloatAlmostEqual(lhs.x(), rhs.x()) &&
- FloatAlmostEqual(lhs.y(), rhs.y())) {
- return ::testing::AssertionSuccess();
- }
- return ::testing::AssertionFailure()
- << "Value of: " << rhs_expr << "\n Actual: " << rhs.ToString()
- << "\nExpected: " << lhs_expr << "\nWhich is: " << lhs.ToString();
-}
-
-::testing::AssertionResult AssertRectFloatEqual(const char* lhs_expr,
- const char* rhs_expr,
- const RectF& lhs,
- const RectF& rhs) {
- if (FloatAlmostEqual(lhs.x(), rhs.x()) &&
- FloatAlmostEqual(lhs.y(), rhs.y()) &&
- FloatAlmostEqual(lhs.width(), rhs.width()) &&
- FloatAlmostEqual(lhs.height(), rhs.height())) {
- return ::testing::AssertionSuccess();
- }
- return ::testing::AssertionFailure()
- << "Value of: " << rhs_expr << "\n Actual: " << rhs.ToString()
- << "\nExpected: " << lhs_expr << "\nWhich is: " << lhs.ToString();
-}
-
-::testing::AssertionResult AssertSkColorsEqual(const char* lhs_expr,
- const char* rhs_expr,
- SkColor lhs,
- SkColor rhs) {
- if (lhs == rhs) {
- return ::testing::AssertionSuccess();
- }
- return ::testing::AssertionFailure() << "Value of: " << rhs_expr
- << "\n Actual: " << ColorAsString(rhs)
- << "\nExpected: " << lhs_expr
- << "\nWhich is: " << ColorAsString(lhs);
-}
-
-::testing::AssertionResult AssertSizeFFloatEqual(const char* lhs_expr,
- const char* rhs_expr,
- const SizeF& lhs,
- const SizeF& rhs) {
- if (FloatAlmostEqual(lhs.width(), rhs.width()) &&
- FloatAlmostEqual(lhs.height(), rhs.height())) {
- return ::testing::AssertionSuccess();
- }
- return ::testing::AssertionFailure()
- << "Value of: " << rhs_expr << "\n Actual: " << rhs.ToString()
- << "\nExpected: " << lhs_expr << "\nWhich is: " << lhs.ToString();
-}
-
-void PrintTo(const AxisTransform2d& transform, ::std::ostream* os) {
- *os << transform.ToString();
-}
-
-void PrintTo(const BoxF& box, ::std::ostream* os) {
- *os << box.ToString();
-}
-
-void PrintTo(const Point& point, ::std::ostream* os) {
- *os << point.ToString();
-}
-
-void PrintTo(const Point3F& point, ::std::ostream* os) {
- *os << point.ToString();
-}
-
-void PrintTo(const PointF& point, ::std::ostream* os) {
- *os << point.ToString();
-}
-
-void PrintTo(const Insets& insets, ::std::ostream* os) {
- *os << insets.ToString();
-}
-
-void PrintTo(const InsetsF& insets, ::std::ostream* os) {
- *os << insets.ToString();
-}
-
-void PrintTo(const QuadF& quad, ::std::ostream* os) {
- *os << quad.ToString();
-}
-
-void PrintTo(const Rect& rect, ::std::ostream* os) {
- *os << rect.ToString();
-}
-
-void PrintTo(const RectF& rect, ::std::ostream* os) {
- *os << rect.ToString();
-}
-
-void PrintTo(const Size& size, ::std::ostream* os) {
- *os << size.ToString();
-}
-
-void PrintTo(const SizeF& size, ::std::ostream* os) {
- *os << size.ToString();
-}
-
-void PrintTo(const Transform& transform, ::std::ostream* os) {
- *os << transform.ToString();
-}
-
-void PrintTo(const Vector2d& vector, ::std::ostream* os) {
- *os << vector.ToString();
-}
-
-void PrintTo(const Vector2dF& vector, ::std::ostream* os) {
- *os << vector.ToString();
-}
-
-void PrintTo(const Vector3dF& vector, ::std::ostream* os) {
- *os << vector.ToString();
-}
-
-} // namespace gfx
diff --git a/ui/gfx/test/gfx_util.h b/ui/gfx/test/gfx_util.h
deleted file mode 100644
index cb59626..0000000
--- a/ui/gfx/test/gfx_util.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_TEST_GFX_UTIL_H_
-#define UI_GFX_TEST_GFX_UTIL_H_
-
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/font_list.h"
-
-namespace gfx {
-
-class AxisTransform2d;
-class BoxF;
-class PointF;
-class RectF;
-class SizeF;
-
-// Tests should use this scoped setter, instead of calling
-// SetDefaultFontDescription directly.
-class ScopedDefaultFontDescription {
- public:
- explicit ScopedDefaultFontDescription(const std::string& font_description) {
- FontList::SetDefaultFontDescription(font_description);
- }
- ~ScopedDefaultFontDescription() {
- FontList::SetDefaultFontDescription(std::string());
- }
-};
-
-#define EXPECT_AXIS_TRANSFORM2D_EQ(a, b) \
- EXPECT_PRED_FORMAT2(::gfx::AssertAxisTransform2dFloatEqual, a, b)
-
-::testing::AssertionResult AssertAxisTransform2dFloatEqual(
- const char* lhs_expr,
- const char* rhs_expr,
- const AxisTransform2d& lhs,
- const AxisTransform2d& rhs);
-
-#define EXPECT_BOXF_EQ(a, b) \
- EXPECT_PRED_FORMAT2(::gfx::AssertBoxFloatEqual, a, b)
-
-::testing::AssertionResult AssertBoxFloatEqual(const char* lhs_expr,
- const char* rhs_expr,
- const BoxF& lhs,
- const BoxF& rhs);
-
-#define EXPECT_POINTF_EQ(a, b) \
- EXPECT_PRED_FORMAT2(::gfx::AssertPointFloatEqual, a, b)
-
-::testing::AssertionResult AssertPointFloatEqual(const char* lhs_expr,
- const char* rhs_expr,
- const PointF& lhs,
- const PointF& rhs);
-
-#define EXPECT_RECTF_EQ(a, b) \
- EXPECT_PRED_FORMAT2(::gfx::AssertRectFloatEqual, a, b)
-
-::testing::AssertionResult AssertRectFloatEqual(const char* lhs_expr,
- const char* rhs_expr,
- const RectF& lhs,
- const RectF& rhs);
-
-#define EXPECT_SKCOLOR_EQ(a, b) \
- EXPECT_PRED_FORMAT2(::gfx::AssertSkColorsEqual, a, b)
-
-::testing::AssertionResult AssertSkColorsEqual(const char* lhs_expr,
- const char* rhs_expr,
- SkColor lhs,
- SkColor rhs);
-
-#define EXPECT_SIZEF_EQ(a, b) \
- EXPECT_PRED_FORMAT2(::gfx::AssertSizeFFloatEqual, a, b)
-
-::testing::AssertionResult AssertSizeFFloatEqual(const char* lhs_expr,
- const char* rhs_expr,
- const SizeF& lhs,
- const SizeF& rhs);
-} // namespace gfx
-
-#endif // UI_GFX_TEST_GFX_UTIL_H_
diff --git a/ui/gfx/test/icc_profiles.cc b/ui/gfx/test/icc_profiles.cc
index 4ec059f..9172e14 100644
--- a/ui/gfx/test/icc_profiles.cc
+++ b/ui/gfx/test/icc_profiles.cc
@@ -1,11 +1,9 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/test/icc_profiles.h"
-#include "base/cxx17_backports.h"
-
namespace gfx {
namespace {
@@ -1897,42 +1895,42 @@
ICCProfile ICCProfileForTestingAdobeRGB() {
return ICCProfile::FromData(
reinterpret_cast<const char*>(adobe_rgb_profile_data),
- base::size(adobe_rgb_profile_data));
+ std::size(adobe_rgb_profile_data));
}
ICCProfile ICCProfileForTestingGenericRGB() {
return ICCProfile::FromData(
reinterpret_cast<const char*>(generic_rgb_profile_data),
- base::size(generic_rgb_profile_data));
+ std::size(generic_rgb_profile_data));
}
ICCProfile ICCProfileForTestingSRGB() {
return ICCProfile::FromData(reinterpret_cast<const char*>(srgb_profile_data),
- base::size(srgb_profile_data));
+ std::size(srgb_profile_data));
}
ICCProfile ICCProfileForTestingColorSpin() {
return ICCProfile::FromData(
reinterpret_cast<const char*>(colorspin_profile_data),
- base::size(colorspin_profile_data));
+ std::size(colorspin_profile_data));
}
ICCProfile ICCProfileForTestingNoAnalyticTrFn() {
return ICCProfile::FromData(
reinterpret_cast<const char*>(no_analytic_tr_fn_profile_data),
- base::size(no_analytic_tr_fn_profile_data));
+ std::size(no_analytic_tr_fn_profile_data));
}
ICCProfile ICCProfileForTestingA2BOnly() {
return ICCProfile::FromData(
reinterpret_cast<const char*>(a2b_only_profile_data),
- base::size(a2b_only_profile_data));
+ std::size(a2b_only_profile_data));
}
ICCProfile ICCProfileForTestingOvershoot() {
return ICCProfile::FromData(
reinterpret_cast<const char*>(overshoot_profile_data),
- base::size(overshoot_profile_data));
+ std::size(overshoot_profile_data));
}
} // namespace gfx
diff --git a/ui/gfx/test/icc_profiles.h b/ui/gfx/test/icc_profiles.h
index 8b13d4a..83883e1 100644
--- a/ui/gfx/test/icc_profiles.h
+++ b/ui/gfx/test/icc_profiles.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/test/run_all_unittests.cc b/ui/gfx/test/run_all_unittests.cc
index e0b546d..80bcbbd 100644
--- a/ui/gfx/test/run_all_unittests.cc
+++ b/ui/gfx/test/run_all_unittests.cc
@@ -1,10 +1,9 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/bind.h"
#include "base/compiler_specific.h"
-#include "base/macros.h"
+#include "base/functional/bind.h"
#include "base/path_service.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_discardable_memory_allocator.h"
@@ -15,15 +14,15 @@
#include "ui/base/ui_base_paths.h"
#include "ui/gfx/font_util.h"
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
#include "base/test/mock_chrome_application_mac.h"
#endif
-#if !defined(OS_IOS)
+#if BUILDFLAG(USE_BLINK)
#include "mojo/core/embedder/embedder.h" // nogncheck
#endif
-#if defined(OS_FUCHSIA)
+#if BUILDFLAG(IS_FUCHSIA)
#include "skia/ext/test_fonts.h" // nogncheck
#endif
@@ -41,7 +40,7 @@
void Initialize() override {
base::TestSuite::Initialize();
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
mock_cr_app::RegisterMockCrApp();
#endif
@@ -51,14 +50,14 @@
ASSERT_TRUE(base::PathService::Get(ui::UI_TEST_PAK, &ui_test_pak_path));
ui::ResourceBundle::InitSharedInstanceWithPakPath(ui_test_pak_path);
-#if defined(OS_ANDROID)
+#if BUILDFLAG(IS_ANDROID)
// Android needs a discardable memory allocator when loading fallback fonts.
base::DiscardableMemoryAllocator::SetInstance(
&discardable_memory_allocator);
#endif
-#if defined(OS_FUCHSIA)
- skia::ConfigureTestFont();
+#if BUILDFLAG(IS_FUCHSIA)
+ skia::InitializeSkFontMgrForTest();
#endif
gfx::InitializeFonts();
@@ -78,7 +77,7 @@
int main(int argc, char** argv) {
GfxTestSuite test_suite(argc, argv);
-#if !defined(OS_IOS)
+#if BUILDFLAG(USE_BLINK)
mojo::core::Init();
#endif
diff --git a/ui/gfx/test/scoped_default_font_description.h b/ui/gfx/test/scoped_default_font_description.h
new file mode 100644
index 0000000..05f0812
--- /dev/null
+++ b/ui/gfx/test/scoped_default_font_description.h
@@ -0,0 +1,26 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_TEST_SCOPED_DEFAULT_FONT_DESCRIPTION_H_
+#define UI_GFX_TEST_SCOPED_DEFAULT_FONT_DESCRIPTION_H_
+
+#include "ui/gfx/font_list.h"
+
+namespace gfx {
+
+// Tests should use this scoped setter, instead of calling
+// SetDefaultFontDescription directly.
+class ScopedDefaultFontDescription {
+ public:
+ explicit ScopedDefaultFontDescription(const std::string& font_description) {
+ FontList::SetDefaultFontDescription(font_description);
+ }
+ ~ScopedDefaultFontDescription() {
+ FontList::SetDefaultFontDescription(std::string());
+ }
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_TEST_SCOPED_DEFAULT_FONT_DESCRIOPTION_H_
diff --git a/ui/gfx/test/sk_color_eq.cc b/ui/gfx/test/sk_color_eq.cc
new file mode 100644
index 0000000..fc35bbe
--- /dev/null
+++ b/ui/gfx/test/sk_color_eq.cc
@@ -0,0 +1,78 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/test/sk_color_eq.h"
+
+#include <iomanip>
+#include <string>
+
+namespace gfx {
+
+namespace {
+
+std::string ColorAsString(SkColor color) {
+ std::ostringstream stream;
+ stream << std::hex << std::uppercase << "#" << std::setfill('0')
+ << std::setw(2) << SkColorGetA(color) << std::setw(2)
+ << SkColorGetR(color) << std::setw(2) << SkColorGetG(color)
+ << std::setw(2) << SkColorGetB(color);
+ return stream.str();
+}
+
+bool ColorComponentsClose(SkColor component1,
+ SkColor component2,
+ int max_deviation) {
+ int c1 = static_cast<int>(component1);
+ int c2 = static_cast<int>(component2);
+ return std::abs(c1 - c2) <= max_deviation;
+}
+
+} // namespace
+
+::testing::AssertionResult AssertSkColorsEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ SkColor lhs,
+ SkColor rhs) {
+ if (lhs == rhs) {
+ return ::testing::AssertionSuccess();
+ }
+ return ::testing::AssertionFailure()
+ << "Expected equality of these values:\n"
+ << lhs_expr << "\n Which is: " << ColorAsString(lhs) << "\n"
+ << rhs_expr << "\n Which is: " << ColorAsString(rhs);
+}
+
+bool ColorsClose(SkColor color1,
+ SkColor color2,
+ int max_per_channel_deviation) {
+ return ColorComponentsClose(SkColorGetR(color1), SkColorGetR(color2),
+ max_per_channel_deviation) &&
+ ColorComponentsClose(SkColorGetG(color1), SkColorGetG(color2),
+ max_per_channel_deviation) &&
+ ColorComponentsClose(SkColorGetB(color1), SkColorGetB(color2),
+ max_per_channel_deviation) &&
+ ColorComponentsClose(SkColorGetA(color1), SkColorGetA(color2),
+ max_per_channel_deviation);
+}
+
+::testing::AssertionResult AssertSkColorsClose(
+ const char* lhs_expr,
+ const char* rhs_expr,
+ const char* max_per_channel_deviation_expr,
+ SkColor lhs,
+ SkColor rhs,
+ int max_per_channel_deviation) {
+ if (ColorsClose(lhs, rhs, max_per_channel_deviation)) {
+ return ::testing::AssertionSuccess();
+ }
+
+ return ::testing::AssertionFailure()
+ << "Expected closeness of these values:\n"
+ << lhs_expr << "\n Which is: " << ColorAsString(lhs) << "\n"
+ << rhs_expr << "\n Which is: " << ColorAsString(rhs) << "\n"
+ << max_per_channel_deviation_expr << " (max per-channel deviation)"
+ << "\n Which is: " << max_per_channel_deviation;
+}
+
+} // namespace gfx
diff --git a/ui/gfx/test/sk_color_eq.h b/ui/gfx/test/sk_color_eq.h
new file mode 100644
index 0000000..0ae21b4
--- /dev/null
+++ b/ui/gfx/test/sk_color_eq.h
@@ -0,0 +1,39 @@
+// Copyright 2021 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_TEST_SK_COLOR_EQ_H_
+#define UI_GFX_TEST_SK_COLOR_EQ_H_
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkColor.h"
+
+namespace gfx {
+
+#define EXPECT_SKCOLOR_EQ(a, b) \
+ EXPECT_PRED_FORMAT2(::gfx::AssertSkColorsEqual, a, b)
+
+::testing::AssertionResult AssertSkColorsEqual(const char* lhs_expr,
+ const char* rhs_expr,
+ SkColor lhs,
+ SkColor rhs);
+
+bool ColorsClose(SkColor color1, SkColor color2, int max_per_channel_deviation);
+
+// Macro for comparing the SkColors that is tolerant of floating point rounding
+// and lossy color space conversions.
+#define EXPECT_SKCOLOR_CLOSE(a, b, max_per_channel_deviation) \
+ EXPECT_PRED_FORMAT3(::gfx::AssertSkColorsClose, a, b, \
+ max_per_channel_deviation)
+
+::testing::AssertionResult AssertSkColorsClose(
+ const char* lhs_expr,
+ const char* rhs_expr,
+ const char* max_per_channel_deviation_expr,
+ SkColor lhs,
+ SkColor rhs,
+ int max_per_channel_deviation);
+
+} // namespace gfx
+
+#endif // UI_GFX_TEST_SK_COLOR_EQ_H_
diff --git a/ui/gfx/text_constants.h b/ui/gfx/text_constants.h
index f22a5d2..2c0b459 100644
--- a/ui/gfx/text_constants.h
+++ b/ui/gfx/text_constants.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/text_elider.cc b/ui/gfx/text_elider.cc
index 211da2e..c9686bb 100644
--- a/ui/gfx/text_elider.cc
+++ b/ui/gfx/text_elider.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
@@ -21,7 +21,8 @@
#include "base/i18n/break_iterator.h"
#include "base/i18n/char_iterator.h"
#include "base/i18n/rtl.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/raw_ref.h"
#include "base/notreached.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -44,7 +45,7 @@
namespace {
-#if defined(OS_IOS)
+#if BUILDFLAG(IS_IOS)
// The returned string will have at least one character besides the ellipsis
// on either side of '@'; if that's impossible, a single ellipsis is returned.
// If possible, only the username is elided. Otherwise, the domain is elided
@@ -136,7 +137,7 @@
std::u16string StringSlicer::CutString(size_t length,
bool insert_ellipsis) const {
const std::u16string ellipsis_text =
- insert_ellipsis ? ellipsis_ : std::u16string();
+ insert_ellipsis ? *ellipsis_ : std::u16string();
// For visual consistency, when eliding at either end of the string, excess
// space should be trimmed from the text to return "Foo bar..." instead of
@@ -144,13 +145,13 @@
if (elide_at_beginning_) {
return ellipsis_text +
- text_.substr(FindValidBoundaryAfter(text_, text_.length() - length,
- elide_whitespace_));
+ text_->substr(FindValidBoundaryAfter(
+ *text_, text_->length() - length, elide_whitespace_));
}
if (!elide_in_middle_) {
- return text_.substr(
- 0, FindValidBoundaryBefore(text_, length, elide_whitespace_)) +
+ return text_->substr(
+ 0, FindValidBoundaryBefore(*text_, length, elide_whitespace_)) +
ellipsis_text;
}
@@ -162,22 +163,22 @@
// less line up; eliminating space would make the text look more ragged.
const size_t half_length = length / 2;
const size_t prefix_length =
- FindValidBoundaryBefore(text_, length - half_length, elide_whitespace_);
+ FindValidBoundaryBefore(*text_, length - half_length, elide_whitespace_);
const size_t suffix_start = FindValidBoundaryAfter(
- text_, text_.length() - half_length, elide_whitespace_);
- return text_.substr(0, prefix_length) + ellipsis_text +
- text_.substr(suffix_start);
+ *text_, text_->length() - half_length, elide_whitespace_);
+ return text_->substr(0, prefix_length) + ellipsis_text +
+ text_->substr(suffix_start);
}
std::u16string ElideFilename(const base::FilePath& filename,
const FontList& font_list,
float available_pixel_width) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
std::u16string filename_utf16 = WideToUTF16(filename.value());
std::u16string extension = WideToUTF16(filename.Extension());
std::u16string rootname =
WideToUTF16(filename.BaseName().RemoveExtension().value());
-#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+#elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
std::u16string filename_utf16 =
WideToUTF16(base::SysNativeMBToWide(filename.value()));
std::u16string extension =
@@ -222,7 +223,7 @@
const FontList& font_list,
float available_pixel_width,
ElideBehavior behavior) {
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
DCHECK_NE(behavior, FADE_TAIL);
std::unique_ptr<RenderText> render_text = RenderText::CreateRenderText();
render_text->SetCursorEnabled(false);
@@ -397,7 +398,7 @@
bool suppressed_;
// String onto which the output is accumulated.
- std::u16string* output_;
+ raw_ptr<std::u16string> output_;
};
void RectangleString::AddString(const std::u16string& input) {
@@ -544,7 +545,7 @@
bool NewLine();
// The font list used for measuring text width.
- const FontList& font_list_;
+ const raw_ref<const FontList> font_list_;
// The height of each line of text.
const int line_height_;
@@ -571,7 +572,7 @@
bool last_line_ended_in_lf_ = false;
// The output vector of lines.
- std::vector<std::u16string>* lines_;
+ raw_ptr<std::vector<std::u16string>> lines_;
// Indicates whether a word was so long that it had to be truncated or elided
// to fit the available width.
@@ -619,7 +620,7 @@
}
void RectangleText::AddLine(const std::u16string& line) {
- const float line_width = GetStringWidthF(line, font_list_);
+ const float line_width = GetStringWidthF(line, *font_list_);
if (line_width <= available_pixel_width_) {
AddToCurrentLineWithWidth(line, line_width);
} else {
@@ -661,7 +662,7 @@
bool first_fragment = true;
while (!insufficient_height_ && !text.empty()) {
std::u16string fragment =
- ElideText(text, font_list_, available_pixel_width_, TRUNCATE);
+ ElideText(text, *font_list_, available_pixel_width_, TRUNCATE);
// At least one character has to be added at every line, even if the
// available space is too small.
if (fragment.empty())
@@ -696,7 +697,7 @@
const ElideBehavior elide_behavior =
(wrap_behavior_ == ELIDE_LONG_WORDS ? ELIDE_TAIL : TRUNCATE);
const std::u16string elided_word =
- ElideText(word, font_list_, available_pixel_width_, elide_behavior);
+ ElideText(word, *font_list_, available_pixel_width_, elide_behavior);
AddToCurrentLine(elided_word);
insufficient_width_ = true;
}
@@ -708,7 +709,7 @@
int lines_added = 0;
std::u16string trimmed;
base::TrimWhitespace(word, base::TRIM_TRAILING, &trimmed);
- const float trimmed_width = GetStringWidthF(trimmed, font_list_);
+ const float trimmed_width = GetStringWidthF(trimmed, *font_list_);
if (trimmed_width <= available_pixel_width_) {
// Word can be made to fit, no need to fragment it.
if ((current_width_ + trimmed_width > available_pixel_width_) && NewLine())
@@ -723,7 +724,7 @@
}
void RectangleText::AddToCurrentLine(const std::u16string& text) {
- AddToCurrentLineWithWidth(text, GetStringWidthF(text, font_list_));
+ AddToCurrentLineWithWidth(text, GetStringWidthF(text, *font_list_));
}
void RectangleText::AddToCurrentLineWithWidth(const std::u16string& text,
diff --git a/ui/gfx/text_elider.h b/ui/gfx/text_elider.h
index 200ad04..c24500f 100644
--- a/ui/gfx/text_elider.h
+++ b/ui/gfx/text_elider.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
@@ -12,7 +12,7 @@
#include <string>
#include <vector>
-#include "base/macros.h"
+#include "base/memory/raw_ref.h"
#include "build/build_config.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/gfx_export.h"
@@ -62,10 +62,10 @@
private:
// The text to be sliced.
- const std::u16string& text_;
+ const raw_ref<const std::u16string, DanglingUntriaged> text_;
// Ellipsis string to use.
- const std::u16string& ellipsis_;
+ const raw_ref<const std::u16string, DanglingUntriaged> ellipsis_;
// If true, the middle of the string will be elided.
const bool elide_in_middle_;
diff --git a/ui/gfx/text_elider_unittest.cc b/ui/gfx/text_elider_unittest.cc
index 579f73b..d55b367 100644
--- a/ui/gfx/text_elider_unittest.cc
+++ b/ui/gfx/text_elider_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
@@ -11,7 +11,6 @@
#include <memory>
#include <vector>
-#include "base/cxx17_backports.h"
#include "base/files/file_path.h"
#include "base/i18n/rtl.h"
#include "base/logging.h"
@@ -85,7 +84,7 @@
};
const FontList font_list;
- for (size_t i = 0; i < base::size(testcases); ++i) {
+ for (size_t i = 0; i < std::size(testcases); ++i) {
const std::u16string expected_output = testcases[i].output;
EXPECT_EQ(
expected_output,
@@ -155,7 +154,7 @@
u"file.name.re…emelylongext"}};
static const FontList font_list;
- for (size_t i = 0; i < base::size(testcases); ++i) {
+ for (size_t i = 0; i < std::size(testcases); ++i) {
base::FilePath filepath(testcases[i].input);
std::u16string expected = testcases[i].output;
std::u16string using_width_of = testcases[i].using_width_of.empty()
@@ -184,7 +183,7 @@
{u"Tests", kTestWidth, u"Test"},
};
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
std::u16string result =
ElideText(cases[i].input, font_list, cases[i].width, TRUNCATE);
EXPECT_EQ(cases[i].output, result);
@@ -208,7 +207,7 @@
{u"Test", kTestWidth, u"Test"},
};
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
std::u16string result =
ElideText(cases[i].input, font_list, cases[i].width, ELIDE_TAIL);
EXPECT_EQ(cases[i].output, result);
@@ -234,7 +233,7 @@
{u"Test123", kEllipsis23Width, u"…23"},
};
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
std::u16string result =
ElideText(cases[i].input, font_list, cases[i].width, ELIDE_HEAD);
EXPECT_EQ(cases[i].output, result);
@@ -259,7 +258,7 @@
// Test that both both UTF-16 surrogate pairs and combining character sequences
// do not get split by ElideText.
TEST(TextEliderTest, ElideTextAtomicSequences) {
-#if defined(OS_WIN)
+#if BUILDFLAG(IS_WIN)
// Needed to bypass DCHECK in GetFallbackFont.
base::test::SingleThreadTaskEnvironment task_environment(
base::test::SingleThreadTaskEnvironment::MainThreadType::UI);
@@ -327,7 +326,7 @@
const FontList font_list;
float ellipsis_width = GetStringWidthF(u"…", font_list);
- for (size_t i = 0; i < base::size(testcases_end); ++i) {
+ for (size_t i = 0; i < std::size(testcases_end); ++i) {
// Compare sizes rather than actual contents because if the test fails,
// output is rather long.
EXPECT_EQ(testcases_end[i].output.size(),
@@ -342,7 +341,7 @@
std::u16string long_string_middle(
data_scheme + std::u16string(number_of_as - number_of_trailing_as, 'a') +
u"…" + std::u16string(number_of_trailing_as, 'a'));
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
long_string_middle += u"…";
#endif
@@ -355,7 +354,7 @@
{data_scheme + million_a, long_string_middle},
};
- for (size_t i = 0; i < base::size(testcases_middle); ++i) {
+ for (size_t i = 0; i < std::size(testcases_middle); ++i) {
// Compare sizes rather than actual contents because if the test fails,
// output is rather long.
EXPECT_EQ(testcases_middle[i].output.size(),
@@ -369,7 +368,7 @@
std::u16string long_string_beginning(u"…" +
std::u16string(number_of_as, 'a'));
-#if !defined(OS_IOS)
+#if !BUILDFLAG(IS_IOS)
long_string_beginning += u"…";
#endif
@@ -381,7 +380,7 @@
{data_scheme + hundred_thousand_a, long_string_beginning},
{data_scheme + million_a, long_string_beginning},
};
- for (size_t i = 0; i < base::size(testcases_beginning); ++i) {
+ for (size_t i = 0; i < std::size(testcases_beginning); ++i) {
EXPECT_EQ(testcases_beginning[i].output.size(),
ElideText(
testcases_beginning[i].input, font_list,
@@ -656,7 +655,7 @@
{u"Hello, my name is Tom", 7, true, u"He...om"},
{u"Hello, my name is Tom", 10, true, u"Hell...Tom"},
{u"Hello, my name is Tom", 100, false, u"Hello, my name is Tom"}};
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
std::u16string output;
EXPECT_EQ(cases[i].result,
ElideString(cases[i].input, cases[i].max_len, &output));
@@ -706,7 +705,7 @@
{u"Te Te Test", test_width, 3 * line_height, false, u"Te|Te|Test"},
};
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
std::vector<std::u16string> lines;
EXPECT_EQ(cases[i].truncated_y ? INSUFFICIENT_SPACE_VERTICAL : 0,
ElideRectangleText(cases[i].input, font_list,
@@ -795,7 +794,7 @@
{u"Test. Test", test_width, line_height * 3, true, false, u"Test|.|Test"},
};
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
std::vector<std::u16string> lines;
const WordWrapBehavior wrap_behavior =
(cases[i].wrap_words ? WRAP_LONG_WORDS : TRUNCATE_LONG_WORDS);
@@ -859,7 +858,7 @@
u"Test|Test|Test|T"},
};
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
std::vector<std::u16string> lines;
EXPECT_EQ(cases[i].truncated_x ? INSUFFICIENT_SPACE_HORIZONTAL : 0,
ElideRectangleText(
@@ -879,7 +878,7 @@
// to wrap incorrectly.
TEST(TextEliderTest, ElideRectangleTextCheckLineWidth) {
FontList font_list;
-#if defined(OS_MAC)
+#if BUILDFLAG(IS_MAC)
// Use a specific font to expose the line width exceeding problem.
font_list = FontList(Font("LucidaGrande", 12));
#endif
@@ -985,7 +984,7 @@
{u"Hi, my name is Tom", 1, 40, false, u"Hi, my name is Tom"},
};
std::u16string output;
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
EXPECT_EQ(cases[i].result,
ElideRectangleString(cases[i].input, cases[i].max_rows,
cases[i].max_cols, true, &output));
@@ -1066,7 +1065,7 @@
{u"Hi, my name_is Dick", 1, 40, false, u"Hi, my name_is Dick"},
};
std::u16string output;
- for (size_t i = 0; i < base::size(cases); ++i) {
+ for (size_t i = 0; i < std::size(cases); ++i) {
EXPECT_EQ(cases[i].result,
ElideRectangleString(cases[i].input, cases[i].max_rows,
cases[i].max_cols, false, &output));
diff --git a/ui/gfx/text_utils.cc b/ui/gfx/text_utils.cc
index 2e73a65..23e3b48 100644
--- a/ui/gfx/text_utils.cc
+++ b/ui/gfx/text_utils.cc
@@ -1,4 +1,4 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -202,7 +202,7 @@
const int cap_height_diff = original_cap_height - to_center_cap_height;
const int new_cap_top =
- original_cap_leading + std::lround(cap_height_diff / 2.0f);
+ original_cap_leading + base::ClampRound(cap_height_diff / 2.0f);
const int new_top = new_cap_top - to_center_leading;
// Since we assume the old font starts at zero, the new top is the adjustment.
diff --git a/ui/gfx/text_utils.h b/ui/gfx/text_utils.h
index b25a001..d3610af 100644
--- a/ui/gfx/text_utils.h
+++ b/ui/gfx/text_utils.h
@@ -1,4 +1,4 @@
-// Copyright 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/text_utils_ios.mm b/ui/gfx/text_utils_ios.mm
index 1f76316..23e8f68 100644
--- a/ui/gfx/text_utils_ios.mm
+++ b/ui/gfx/text_utils_ios.mm
@@ -1,13 +1,15 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/text_utils.h"
+#import <CoreText/CoreText.h>
#import <UIKit/UIKit.h>
#include <cmath>
+#include "base/mac/foundation_util.h"
#include "base/strings/sys_string_conversions.h"
#include "ui/gfx/font_list.h"
@@ -19,8 +21,9 @@
float GetStringWidthF(const std::u16string& text, const FontList& font_list) {
NSString* ns_text = base::SysUTF16ToNSString(text);
- NativeFont native_font = font_list.GetPrimaryFont().GetNativeFont();
- NSDictionary* attributes = @{NSFontAttributeName : native_font};
+ CTFontRef font = font_list.GetPrimaryFont().GetCTFont();
+ NSDictionary* attributes =
+ @{NSFontAttributeName : base::mac::CFToNSCast(font)};
return [ns_text sizeWithAttributes:attributes].width;
}
diff --git a/ui/gfx/text_utils_skia.cc b/ui/gfx/text_utils_skia.cc
index 2c8e96c..0877864 100644
--- a/ui/gfx/text_utils_skia.cc
+++ b/ui/gfx/text_utils_skia.cc
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/text_utils_unittest.cc b/ui/gfx/text_utils_unittest.cc
index f1824dc..f80b978 100644
--- a/ui/gfx/text_utils_unittest.cc
+++ b/ui/gfx/text_utils_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright 2011 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -77,7 +77,7 @@
// Adjust a border with a small vertical component. The vertical component
// should go to zero because it overlaps the leading and descender areas of
// the font.
- constexpr gfx::Insets kSmallVerticalInsets(1, 20);
+ constexpr auto kSmallVerticalInsets = gfx::Insets::VH(1, 20);
const gfx::Insets result =
AdjustVisualBorderForFont(font_list, kSmallVerticalInsets);
EXPECT_EQ(result.left(), kSmallVerticalInsets.left());
diff --git a/ui/gfx/ubidi_deleter.h b/ui/gfx/ubidi_deleter.h
new file mode 100644
index 0000000..5476e8d
--- /dev/null
+++ b/ui/gfx/ubidi_deleter.h
@@ -0,0 +1,21 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_UBIDI_DELETER_H_
+#define UI_GFX_UBIDI_DELETER_H_
+
+#include "third_party/icu/source/common/unicode/ubidi.h"
+
+namespace ui::gfx {
+
+struct UBiDiDeleter {
+ void operator()(UBiDi* bidi) {
+ if (bidi)
+ ubidi_close(bidi);
+ }
+};
+
+} // namespace ui::gfx
+
+#endif // UI_GFX_UBIDI_DELETER_H_
diff --git a/ui/gfx/ui_gfx_exports.cc b/ui/gfx/ui_gfx_exports.cc
index ca95eb3..a74de9d 100644
--- a/ui/gfx/ui_gfx_exports.cc
+++ b/ui/gfx/ui_gfx_exports.cc
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/utf16_indexing.cc b/ui/gfx/utf16_indexing.cc
index 164db80..0962164 100644
--- a/ui/gfx/utf16_indexing.cc
+++ b/ui/gfx/utf16_indexing.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/utf16_indexing.h b/ui/gfx/utf16_indexing.h
index 4831c41..e3df352 100644
--- a/ui/gfx/utf16_indexing.h
+++ b/ui/gfx/utf16_indexing.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/utf16_indexing_unittest.cc b/ui/gfx/utf16_indexing_unittest.cc
index 289fd44..002becb 100644
--- a/ui/gfx/utf16_indexing_unittest.cc
+++ b/ui/gfx/utf16_indexing_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/vector_icon_types.h b/ui/gfx/vector_icon_types.h
index d4ffcdd..64ee43d 100644
--- a/ui/gfx/vector_icon_types.h
+++ b/ui/gfx/vector_icon_types.h
@@ -1,11 +1,11 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_VECTOR_ICON_TYPES_H_
#define UI_GFX_VECTOR_ICON_TYPES_H_
-#include "base/macros.h"
+#include "base/memory/raw_ptr_exclusion.h"
#include "third_party/skia/include/core/SkScalar.h"
#include "ui/gfx/animation/tween.h"
@@ -87,11 +87,15 @@
// size or range of sizes.
struct VectorIconRep {
VectorIconRep() = default;
+ constexpr VectorIconRep(const PathElement* path, size_t path_size)
+ : path(path), path_size(path_size) {}
VectorIconRep(const VectorIconRep&) = delete;
VectorIconRep& operator=(const VectorIconRep&) = delete;
- const PathElement* path = nullptr;
+ // This field is not a raw_ptr<> because it was filtered by the rewriter for:
+ // #global-scope, #constexpr-ctor-field-initializer
+ RAW_PTR_EXCLUSION const PathElement* path = nullptr;
// The length of |path|.
size_t path_size = 0u;
@@ -101,13 +105,19 @@
// scale factors and pixel dimensions.
struct VectorIcon {
VectorIcon() = default;
+ constexpr VectorIcon(const VectorIconRep* reps,
+ size_t reps_size,
+ const char* name)
+ : reps(reps), reps_size(reps_size), name(name) {}
VectorIcon(const VectorIcon&) = delete;
VectorIcon& operator=(const VectorIcon&) = delete;
bool is_empty() const { return !reps; }
- const VectorIconRep* const reps = nullptr;
+ // This field is not a raw_ptr<> because it was filtered by the rewriter for:
+ // #global-scope, #constexpr-ctor-field-initializer
+ RAW_PTR_EXCLUSION const VectorIconRep* const reps = nullptr;
size_t reps_size = 0u;
// A human-readable name, useful for debugging, derived from the name of the
diff --git a/ui/gfx/vector_icon_utils.cc b/ui/gfx/vector_icon_utils.cc
index 44b68fa..5e031d3 100644
--- a/ui/gfx/vector_icon_utils.cc
+++ b/ui/gfx/vector_icon_utils.cc
@@ -1,10 +1,12 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/vector_icon_utils.h"
-#include "base/check.h"
+#include <ostream>
+
+#include "base/check_op.h"
#include "ui/gfx/vector_icon_types.h"
namespace gfx {
diff --git a/ui/gfx/vector_icon_utils.h b/ui/gfx/vector_icon_utils.h
index 532f29f..d66c019 100644
--- a/ui/gfx/vector_icon_utils.h
+++ b/ui/gfx/vector_icon_utils.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/video_types.h b/ui/gfx/video_types.h
index e8865a6..3ff104f 100644
--- a/ui/gfx/video_types.h
+++ b/ui/gfx/video_types.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/vsync_provider.cc b/ui/gfx/vsync_provider.cc
index ff4b4a5..ccf14d9 100644
--- a/ui/gfx/vsync_provider.cc
+++ b/ui/gfx/vsync_provider.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/vsync_provider.h b/ui/gfx/vsync_provider.h
index 87b0a15..fcc739d 100644
--- a/ui/gfx/vsync_provider.h
+++ b/ui/gfx/vsync_provider.h
@@ -1,11 +1,11 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_VSYNC_PROVIDER_H_
#define UI_GFX_VSYNC_PROVIDER_H_
-#include "base/callback.h"
+#include "base/functional/callback.h"
#include "base/time/time.h"
#include "ui/gfx/gfx_export.h"
diff --git a/ui/gfx/win/crash_id_helper.cc b/ui/gfx/win/crash_id_helper.cc
index 5cbf920..a5d9eb6 100644
--- a/ui/gfx/win/crash_id_helper.cc
+++ b/ui/gfx/win/crash_id_helper.cc
@@ -1,10 +1,11 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/win/crash_id_helper.h"
#include "base/memory/ptr_util.h"
+#include "base/no_destructor.h"
#include "base/strings/string_util.h"
namespace gfx {
diff --git a/ui/gfx/win/crash_id_helper.h b/ui/gfx/win/crash_id_helper.h
index 649e203..11048a2 100644
--- a/ui/gfx/win/crash_id_helper.h
+++ b/ui/gfx/win/crash_id_helper.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,7 +8,6 @@
#include <string>
#include <vector>
-#include "base/macros.h"
#include "base/no_destructor.h"
#include "base/threading/platform_thread.h"
#include "components/crash/core/common/crash_key.h"
diff --git a/ui/gfx/win/crash_id_helper_unittest.cc b/ui/gfx/win/crash_id_helper_unittest.cc
index 5e3e509..98b052d 100644
--- a/ui/gfx/win/crash_id_helper_unittest.cc
+++ b/ui/gfx/win/crash_id_helper_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/win/direct_write.cc b/ui/gfx/win/direct_write.cc
index fc7356b..bc17d6e 100644
--- a/ui/gfx/win/direct_write.cc
+++ b/ui/gfx/win/direct_write.cc
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,11 +9,9 @@
#include <string>
#include "base/debug/alias.h"
-#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/utf_string_conversions.h"
#include "base/trace_event/trace_event.h"
-#include "base/win/windows_version.h"
#include "skia/ext/fontmgr_default.h"
#include "third_party/skia/include/core/SkFontMgr.h"
#include "third_party/skia/include/ports/SkTypeface_win.h"
@@ -62,37 +60,11 @@
CHECK(!!factory);
SetDirectWriteFactory(factory.Get());
- // The skia call to create a new DirectWrite font manager instance can fail
- // if we are unable to get the system font collection from the DirectWrite
- // factory. The GetSystemFontCollection method in the IDWriteFactory
- // interface fails with E_INVALIDARG on certain Windows 7 gold versions
- // (6.1.7600.*).
sk_sp<SkFontMgr> direct_write_font_mgr =
SkFontMgr_New_DirectWrite(factory.Get());
- int iteration = 0;
- if (!direct_write_font_mgr &&
- base::win::GetVersion() == base::win::Version::WIN7) {
- // Windows (win7_rtm) may fail to map the service sections
- // (crbug.com/956064).
- constexpr int kMaxRetries = 5;
- constexpr base::TimeDelta kRetrySleepTime = base::Microseconds(500);
- while (iteration < kMaxRetries) {
- base::PlatformThread::Sleep(kRetrySleepTime);
- direct_write_font_mgr = SkFontMgr_New_DirectWrite(factory.Get());
- if (direct_write_font_mgr)
- break;
- ++iteration;
- }
- }
- if (!direct_write_font_mgr)
- iteration = -1;
- base::UmaHistogramSparse("DirectWrite.Fonts.Gfx.InitializeLoopCount",
- iteration);
- // TODO(crbug.com/956064): Move to a CHECK when the cause of the crash is
- // fixed and remove the if statement that fallback to GDI font manager.
- DCHECK(!!direct_write_font_mgr);
- if (!direct_write_font_mgr)
+ if (!direct_write_font_mgr) {
direct_write_font_mgr = SkFontMgr_New_GDI();
+ }
// Override the default skia font manager. This must be called before any
// use of the skia font manager is done (e.g. before any call to
diff --git a/ui/gfx/win/direct_write.h b/ui/gfx/win/direct_write.h
index 2cbb4a5..7202205 100644
--- a/ui/gfx/win/direct_write.h
+++ b/ui/gfx/win/direct_write.h
@@ -1,4 +1,4 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/win/direct_write_unittest.cc b/ui/gfx/win/direct_write_unittest.cc
index 1c136c8..d93d188 100644
--- a/ui/gfx/win/direct_write_unittest.cc
+++ b/ui/gfx/win/direct_write_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/win/hwnd_util.cc b/ui/gfx/win/hwnd_util.cc
index 286b766..c732cc0 100644
--- a/ui/gfx/win/hwnd_util.cc
+++ b/ui/gfx/win/hwnd_util.cc
@@ -1,9 +1,10 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/win/hwnd_util.h"
+#include <dwmapi.h> // DWMWA_CLOAKED
#include <windows.h>
#include "base/debug/gdi_debug_util_win.h"
@@ -114,6 +115,36 @@
return reinterpret_cast<void*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
}
+bool IsWindowCloaked(HWND hwnd) {
+ BOOL is_cloaked = FALSE;
+ return SUCCEEDED(DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED, &is_cloaked,
+ sizeof(is_cloaked))) &&
+ is_cloaked;
+}
+
+absl::optional<bool> IsWindowOnCurrentVirtualDesktop(
+ HWND window,
+ Microsoft::WRL::ComPtr<IVirtualDesktopManager> virtual_desktop_manager) {
+ BOOL on_current_desktop;
+ if (FAILED(virtual_desktop_manager->IsWindowOnCurrentVirtualDesktop(
+ window, &on_current_desktop))) {
+ return absl::nullopt;
+ }
+ if (on_current_desktop)
+ return true;
+
+ // IsWindowOnCurrentVirtualDesktop() is flaky for newly opened windows,
+ // which causes test flakiness. Occasionally, it incorrectly says a window
+ // is not on the current virtual desktop when it is. In this situation,
+ // it also returns GUID_NULL for the desktop id.
+ GUID workspace_guid;
+ if (FAILED(virtual_desktop_manager->GetWindowDesktopId(window,
+ &workspace_guid))) {
+ return absl::nullopt;
+ }
+ return workspace_guid == GUID_NULL;
+}
+
#pragma warning(pop)
bool DoesWindowBelongToActiveWindow(HWND window) {
@@ -186,6 +217,7 @@
if (!hwnd) {
switch (last_error) {
case ERROR_NOT_ENOUGH_MEMORY:
+ case ERROR_NO_MORE_USER_HANDLES:
base::debug::CollectGDIUsageAndDie();
break;
case ERROR_ACCESS_DENIED:
diff --git a/ui/gfx/win/hwnd_util.h b/ui/gfx/win/hwnd_util.h
index d4d8eaf..92635e4 100644
--- a/ui/gfx/win/hwnd_util.h
+++ b/ui/gfx/win/hwnd_util.h
@@ -1,14 +1,17 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_WIN_HWND_UTIL_H_
#define UI_GFX_WIN_HWND_UTIL_H_
+#include <shobjidl.h> // Must be before propkey.
#include <windows.h>
+#include <wrl/client.h>
#include <string>
+#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/gfx/gfx_export.h"
namespace gfx {
@@ -30,6 +33,18 @@
// of its children.
GFX_EXPORT bool DoesWindowBelongToActiveWindow(HWND window);
+// Returns true if the specified window is cloaked. Windows 10 and later
+// have cloaked windows which are windows with WS_VISIBLE attribute but not
+// displayed.
+GFX_EXPORT bool IsWindowCloaked(HWND hwnd);
+
+// Returns true if `window` is on the current virtual desktop, false if isn't,
+// and absl::nullopt if a COM method fails. Since this calls COM methods,
+// it can only be called from a COM thread.
+GFX_EXPORT absl::optional<bool> IsWindowOnCurrentVirtualDesktop(
+ HWND window,
+ Microsoft::WRL::ComPtr<IVirtualDesktopManager> virtual_desktop_manager);
+
// Sizes the window to have a window size of |pref|, then centers the window
// over |parent|, ensuring the window fits on screen.
GFX_EXPORT void CenterAndSizeWindow(HWND parent,
diff --git a/ui/gfx/win/msg_util.h b/ui/gfx/win/msg_util.h
index 7c6b42b..45d41b6 100644
--- a/ui/gfx/win/msg_util.h
+++ b/ui/gfx/win/msg_util.h
@@ -1,10 +1,12 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2014 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_WIN_MSG_UTIL_H_
#define UI_GFX_WIN_MSG_UTIL_H_
+#include <ostream>
+
#include "base/memory/weak_ptr.h"
#include "base/notreached.h"
#include "ui/gfx/geometry/point.h"
diff --git a/ui/gfx/win/physical_size.cc b/ui/gfx/win/physical_size.cc
index 39978f7..9b7c9dc 100644
--- a/ui/gfx/win/physical_size.cc
+++ b/ui/gfx/win/physical_size.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/win/physical_size.h b/ui/gfx/win/physical_size.h
index 5b768ad..8428147 100644
--- a/ui/gfx/win/physical_size.h
+++ b/ui/gfx/win/physical_size.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/win/rendering_window_manager.cc b/ui/gfx/win/rendering_window_manager.cc
index 8536882..52e8bdd 100644
--- a/ui/gfx/win/rendering_window_manager.cc
+++ b/ui/gfx/win/rendering_window_manager.cc
@@ -1,14 +1,13 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/win/rendering_window_manager.h"
-#include "base/bind.h"
+#include "base/functional/bind.h"
#include "base/logging.h"
#include "base/no_destructor.h"
-#include "base/single_thread_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/single_thread_task_runner.h"
namespace gfx {
@@ -73,7 +72,7 @@
}
RenderingWindowManager::RenderingWindowManager()
- : task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
+ : task_runner_(base::SingleThreadTaskRunner::GetCurrentDefault()) {}
RenderingWindowManager::~RenderingWindowManager() = default;
diff --git a/ui/gfx/win/rendering_window_manager.h b/ui/gfx/win/rendering_window_manager.h
index dd729b1..b97555e 100644
--- a/ui/gfx/win/rendering_window_manager.h
+++ b/ui/gfx/win/rendering_window_manager.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/win/scoped_set_map_mode.h b/ui/gfx/win/scoped_set_map_mode.h
index f5669fe..ab06ead 100644
--- a/ui/gfx/win/scoped_set_map_mode.h
+++ b/ui/gfx/win/scoped_set_map_mode.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,7 +8,6 @@
#include <windows.h>
#include "base/check_op.h"
-#include "base/macros.h"
namespace gfx {
diff --git a/ui/gfx/win/singleton_hwnd.cc b/ui/gfx/win/singleton_hwnd.cc
index 1476b11..489c4ae 100644
--- a/ui/gfx/win/singleton_hwnd.cc
+++ b/ui/gfx/win/singleton_hwnd.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/win/singleton_hwnd.h b/ui/gfx/win/singleton_hwnd.h
index 36daf55..6a5fbe5 100644
--- a/ui/gfx/win/singleton_hwnd.h
+++ b/ui/gfx/win/singleton_hwnd.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,7 +7,6 @@
#include <windows.h>
-#include "base/macros.h"
#include "base/observer_list.h"
#include "ui/gfx/gfx_export.h"
#include "ui/gfx/win/window_impl.h"
diff --git a/ui/gfx/win/singleton_hwnd_hot_key_observer.cc b/ui/gfx/win/singleton_hwnd_hot_key_observer.cc
index be3d7c2..47d90ce 100644
--- a/ui/gfx/win/singleton_hwnd_hot_key_observer.cc
+++ b/ui/gfx/win/singleton_hwnd_hot_key_observer.cc
@@ -1,11 +1,11 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/win/singleton_hwnd_hot_key_observer.h"
-#include "base/bind.h"
#include "base/containers/flat_set.h"
+#include "base/functional/bind.h"
#include "base/memory/ptr_util.h"
#include "base/no_destructor.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
diff --git a/ui/gfx/win/singleton_hwnd_hot_key_observer.h b/ui/gfx/win/singleton_hwnd_hot_key_observer.h
index 5b003ce..cbb1e9a 100644
--- a/ui/gfx/win/singleton_hwnd_hot_key_observer.h
+++ b/ui/gfx/win/singleton_hwnd_hot_key_observer.h
@@ -1,4 +1,4 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/win/singleton_hwnd_observer.cc b/ui/gfx/win/singleton_hwnd_observer.cc
index f439105..229b98a 100644
--- a/ui/gfx/win/singleton_hwnd_observer.cc
+++ b/ui/gfx/win/singleton_hwnd_observer.cc
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/win/singleton_hwnd_observer.h b/ui/gfx/win/singleton_hwnd_observer.h
index cc2ef8a..7342102 100644
--- a/ui/gfx/win/singleton_hwnd_observer.h
+++ b/ui/gfx/win/singleton_hwnd_observer.h
@@ -1,4 +1,4 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
+// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -7,8 +7,7 @@
#include <windows.h>
-#include "base/callback.h"
-#include "base/macros.h"
+#include "base/functional/callback.h"
#include "ui/gfx/gfx_export.h"
namespace gfx {
diff --git a/ui/gfx/win/text_analysis_source.cc b/ui/gfx/win/text_analysis_source.cc
index 13fef96..03db0c4 100644
--- a/ui/gfx/win/text_analysis_source.cc
+++ b/ui/gfx/win/text_analysis_source.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/win/text_analysis_source.h b/ui/gfx/win/text_analysis_source.h
index 93ce417..3abf2b2 100644
--- a/ui/gfx/win/text_analysis_source.h
+++ b/ui/gfx/win/text_analysis_source.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -10,7 +10,6 @@
#include <string>
-#include "base/macros.h"
#include "ui/gfx/gfx_export.h"
namespace gfx {
diff --git a/ui/gfx/win/text_analysis_source_unittest.cc b/ui/gfx/win/text_analysis_source_unittest.cc
index 7886218..6f15c37 100644
--- a/ui/gfx/win/text_analysis_source_unittest.cc
+++ b/ui/gfx/win/text_analysis_source_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/win/window_impl.cc b/ui/gfx/win/window_impl.cc
index 0fdf80b..29991b0 100644
--- a/ui/gfx/win/window_impl.cc
+++ b/ui/gfx/win/window_impl.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,11 +6,10 @@
#include <list>
-#include "base/bind.h"
-#include "base/cxx17_backports.h"
+#include "base/at_exit.h"
#include "base/debug/alias.h"
+#include "base/functional/bind.h"
#include "base/logging.h"
-#include "base/macros.h"
#include "base/memory/singleton.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
@@ -145,7 +144,7 @@
auto last_error = ::GetLastError();
base::debug::Alias(&last_error);
wchar_t name_copy[64];
- base::wcslcpy(name_copy, name.c_str(), base::size(name_copy));
+ base::wcslcpy(name_copy, name.c_str(), std::size(name_copy));
base::debug::Alias(name_copy);
PCHECK(atom);
}
diff --git a/ui/gfx/win/window_impl.h b/ui/gfx/win/window_impl.h
index 2a5683b..d927724 100644
--- a/ui/gfx/win/window_impl.h
+++ b/ui/gfx/win/window_impl.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,7 +8,6 @@
#include <string>
#include "base/check_op.h"
-#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/gfx_export.h"
diff --git a/ui/gfx/x/BUILD.gn b/ui/gfx/x/BUILD.gn
index 87ce467..6236351 100644
--- a/ui/gfx/x/BUILD.gn
+++ b/ui/gfx/x/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
+# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -6,7 +6,7 @@
import("//build/config/ui.gni")
import("//tools/generate_library_loader/generate_library_loader.gni")
-assert(use_x11 || ozone_platform_x11)
+assert(ozone_platform_x11)
declare_args() {
regenerate_x11_protos = false
@@ -19,6 +19,8 @@
config("build_xprotos_config") {
cflags = [
+ "-Wno-shadow",
+
# Generated proto files pull all fields from a struct into scope
# even if they aren't used. Rather than adding logic in the
# generator to determine which fields are used and keeping only
@@ -156,6 +158,7 @@
"error.h",
"event.cc",
"event.h",
+ "future.cc",
"future.h",
"keyboard_state.cc",
"keyboard_state.h",
@@ -163,8 +166,6 @@
"ref_counted_fd.h",
"scoped_ignore_errors.cc",
"scoped_ignore_errors.h",
- "x11_switches.cc",
- "x11_switches.h",
"xlib_support.cc",
"xlib_support.h",
"xproto_internal.cc",
@@ -180,6 +181,7 @@
"//base",
"//base:i18n",
"//ui/events/platform",
+ "//ui/gfx:gfx_switches",
]
public_deps = [
":build_xprotos",
@@ -195,6 +197,8 @@
sources = [
"property_cache.cc",
"property_cache.h",
+ "window_cache.cc",
+ "window_cache.h",
"x11_atom_cache.cc",
"x11_atom_cache.h",
"x11_path.cc",
@@ -208,6 +212,7 @@
deps = [
"//base",
"//skia",
+ "//ui/gfx/geometry",
]
public_deps = [ ":xproto" ]
}
@@ -217,10 +222,12 @@
sources = [
"connection_unittest.cc",
"property_cache_unittest.cc",
+ "window_cache_unittest.cc",
]
deps = [
"//base",
"//testing/gtest",
+ "//ui/gfx/geometry",
"//ui/gfx/x",
]
}
diff --git a/ui/gfx/x/connection.cc b/ui/gfx/x/connection.cc
index cf033f9..9b8998b 100644
--- a/ui/gfx/x/connection.cc
+++ b/ui/gfx/x/connection.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -15,13 +15,14 @@
#include "base/memory/ptr_util.h"
#include "base/memory/scoped_refptr.h"
#include "base/no_destructor.h"
+#include "base/observer_list.h"
#include "base/threading/thread_local.h"
#include "base/trace_event/trace_event.h"
+#include "ui/gfx/switches.h"
#include "ui/gfx/x/bigreq.h"
#include "ui/gfx/x/event.h"
#include "ui/gfx/x/keyboard_state.h"
#include "ui/gfx/x/randr.h"
-#include "ui/gfx/x/x11_switches.h"
#include "ui/gfx/x/xkb.h"
#include "ui/gfx/x/xproto.h"
#include "ui/gfx/x/xproto_internal.h"
@@ -31,27 +32,6 @@
namespace {
-// On the wire, sequence IDs are 16 bits. In xcb, they're usually extended to
-// 32 and sometimes 64 bits. In Xlib, they're extended to unsigned long, which
-// may be 32 or 64 bits depending on the platform. This function is intended to
-// prevent bugs caused by comparing two differently sized sequences. Also
-// handles rollover. To use, compare the result of this function with 0. For
-// example, to compare seq1 <= seq2, use CompareSequenceIds(seq1, seq2) <= 0.
-template <typename T, typename U>
-auto CompareSequenceIds(T t, U u) {
- static_assert(std::is_unsigned<T>::value, "");
- static_assert(std::is_unsigned<U>::value, "");
- // Cast to the smaller of the two types so that comparisons will always work.
- // If we casted to the larger type, then the smaller type will be zero-padded
- // and may incorrectly compare less than the other value.
- using SmallerType =
- typename std::conditional<sizeof(T) <= sizeof(U), T, U>::type;
- SmallerType t0 = static_cast<SmallerType>(t);
- SmallerType u0 = static_cast<SmallerType>(u);
- using SignedType = typename std::make_signed<SmallerType>::type;
- return static_cast<SignedType>(t0 - u0);
-}
-
base::ThreadLocalOwnedPointer<Connection>& GetConnectionTLS() {
static base::NoDestructor<base::ThreadLocalOwnedPointer<Connection>> tls;
return *tls;
@@ -120,11 +100,12 @@
? base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kX11Display)
: address),
+ connection_(xcb_connect(display_string_.empty() ? nullptr
+ : display_string_.c_str(),
+ &default_screen_id_),
+ xcb_disconnect),
error_handler_(base::BindRepeating(DefaultErrorHandler)),
io_error_handler_(base::BindOnce(DefaultIOErrorHandler)) {
- connection_ =
- xcb_connect(display_string_.empty() ? nullptr : display_string_.c_str(),
- &default_screen_id_);
DCHECK(connection_);
if (Ready()) {
auto buf = ReadBuffer(base::MakeRefCounted<UnretainedRefCountedMemory>(
@@ -182,7 +163,6 @@
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
platform_event_source.reset();
- xcb_disconnect(connection_);
}
size_t Connection::MaxRequestSizeInBytes() const {
@@ -208,12 +188,20 @@
void Connection::FutureImpl::Wait() {
connection->WaitForResponse(this);
+}
+
+void Connection::FutureImpl::DispatchNow() {
+ Wait();
ProcessResponse();
}
+bool Connection::FutureImpl::AfterEvent(const Event& event) const {
+ return CompareSequenceIds(event.sequence(), sequence) > 0;
+}
+
void Connection::FutureImpl::Sync(RawReply* raw_reply,
std::unique_ptr<Error>* error) {
- connection->WaitForResponse(this);
+ Wait();
TakeResponse(raw_reply, error);
}
@@ -335,12 +323,12 @@
bool Connection::Ready() const {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- return !xcb_connection_has_error(connection_);
+ return !xcb_connection_has_error(connection_.get());
}
void Connection::Flush() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- xcb_flush(connection_);
+ xcb_flush(connection_.get());
}
void Connection::Sync() {
@@ -492,9 +480,9 @@
xcb_connection_t* Connection::XcbConnection() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- if (io_error_handler_ && xcb_connection_has_error(connection_))
+ if (io_error_handler_ && xcb_connection_has_error(connection_.get()))
std::move(io_error_handler_).Run();
- return connection_;
+ return connection_.get();
}
void Connection::InitRootDepthAndVisual() {
@@ -767,7 +755,7 @@
}
uint32_t Connection::GenerateIdImpl() {
- return xcb_generate_id(connection_);
+ return xcb_generate_id(connection_.get());
}
} // namespace x11
diff --git a/ui/gfx/x/connection.h b/ui/gfx/x/connection.h
index 4281481..c19cc04 100644
--- a/ui/gfx/x/connection.h
+++ b/ui/gfx/x/connection.h
@@ -1,14 +1,16 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_X_CONNECTION_H_
#define UI_GFX_X_CONNECTION_H_
-#include "base/callback.h"
#include "base/component_export.h"
#include "base/containers/circular_deque.h"
#include "base/containers/flat_map.h"
+#include "base/functional/callback.h"
+#include "base/memory/raw_ptr.h"
+#include "base/observer_list.h"
#include "base/sequence_checker.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "ui/events/platform/platform_event_source.h"
@@ -24,6 +26,27 @@
class KeyboardState;
class WriteBuffer;
+// On the wire, sequence IDs are 16 bits. In xcb, they're usually extended to
+// 32 and sometimes 64 bits. In Xlib, they're extended to unsigned long, which
+// may be 32 or 64 bits depending on the platform. This function is intended to
+// prevent bugs caused by comparing two differently sized sequences. Also
+// handles rollover. To use, compare the result of this function with 0. For
+// example, to compare seq1 <= seq2, use CompareSequenceIds(seq1, seq2) <= 0.
+template <typename T, typename U>
+auto CompareSequenceIds(T t, U u) {
+ static_assert(std::is_unsigned<T>::value, "");
+ static_assert(std::is_unsigned<U>::value, "");
+ // Cast to the smaller of the two types so that comparisons will always work.
+ // If we casted to the larger type, then the smaller type will be zero-padded
+ // and may incorrectly compare less than the other value.
+ using SmallerType =
+ typename std::conditional<sizeof(T) <= sizeof(U), T, U>::type;
+ SmallerType t0 = static_cast<SmallerType>(t);
+ SmallerType u0 = static_cast<SmallerType>(u);
+ using SignedType = typename std::make_signed<SmallerType>::type;
+ return static_cast<SignedType>(t0 - u0);
+}
+
// This interface is used by classes wanting to receive
// Events directly. For input events (mouse, keyboard, touch), a
// PlatformEventObserver should be used instead.
@@ -51,8 +74,8 @@
using SequenceType = unsigned int;
struct VisualInfo {
- const Format* format;
- const VisualType* visual_type;
+ raw_ptr<const Format> format;
+ raw_ptr<const VisualType> visual_type;
};
// Gets or creates the thread local connection instance.
@@ -204,6 +227,7 @@
std::unique_ptr<ui::PlatformEventSource> platform_event_source;
private:
+ friend class FutureBase;
template <typename Reply>
friend class Future;
@@ -216,6 +240,10 @@
void Wait();
+ void DispatchNow();
+
+ bool AfterEvent(const Event& event) const;
+
void Sync(RawReply* raw_reply, std::unique_ptr<Error>* error);
void OnResponse(ResponseCallback callback);
@@ -234,7 +262,7 @@
// The response must already have been obtained using WaitForResponse().
void TakeResponse(RawReply* reply, std::unique_ptr<Error>* error);
- Connection* connection = nullptr;
+ raw_ptr<Connection, DanglingUntriaged> connection = nullptr;
SequenceType sequence = 0;
bool generates_reply = false;
const char* request_name_for_tracing = nullptr;
@@ -298,7 +326,10 @@
uint32_t GenerateIdImpl();
- xcb_connection_t* connection_ = nullptr;
+ std::string display_string_;
+ int default_screen_id_ = 0;
+ std::unique_ptr<xcb_connection_t, void (*)(xcb_connection_t*)> connection_ = {
+ nullptr, nullptr};
std::unique_ptr<XlibDisplay> xlib_display_;
bool synchronous_ = false;
@@ -306,12 +337,10 @@
uint32_t extended_max_request_length_ = 0;
- std::string display_string_;
- int default_screen_id_ = 0;
Setup setup_;
- Screen* default_screen_ = nullptr;
- Depth* default_root_depth_ = nullptr;
- VisualType* default_root_visual_ = nullptr;
+ raw_ptr<Screen> default_screen_ = nullptr;
+ raw_ptr<Depth> default_root_depth_ = nullptr;
+ raw_ptr<VisualType> default_root_visual_ = nullptr;
base::flat_map<VisualId, VisualInfo> default_screen_visuals_;
@@ -322,7 +351,7 @@
base::ObserverList<EventObserver>::Unchecked event_observers_;
// The Event currently being dispatched, or nullptr if there is none.
- const Event* dispatching_event_ = nullptr;
+ raw_ptr<const Event> dispatching_event_ = nullptr;
base::circular_deque<Request> requests_;
// The sequence ID of requests_.front(), or if |requests_| is empty, then the
diff --git a/ui/gfx/x/connection_unittest.cc b/ui/gfx/x/connection_unittest.cc
index 46928a7..a600cbc 100644
--- a/ui/gfx/x/connection_unittest.cc
+++ b/ui/gfx/x/connection_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/error.cc b/ui/gfx/x/error.cc
index f33de1a..d12069e 100644
--- a/ui/gfx/x/error.cc
+++ b/ui/gfx/x/error.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/error.h b/ui/gfx/x/error.h
index a9de90b..9420888 100644
--- a/ui/gfx/x/error.h
+++ b/ui/gfx/x/error.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/event.cc b/ui/gfx/x/event.cc
index 68d6946..002a088 100644
--- a/ui/gfx/x/event.cc
+++ b/ui/gfx/x/event.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -23,17 +23,17 @@
Connection* connection) {
auto* xcb_event = reinterpret_cast<xcb_generic_event_t*>(
const_cast<uint8_t*>(event_bytes->data()));
+ uint8_t response_type = xcb_event->response_type & ~kSendEventMask;
+ send_event_ = xcb_event->response_type & kSendEventMask;
sequence_ = xcb_event->full_sequence;
// KeymapNotify events are the only events that don't have a sequence.
- if ((xcb_event->response_type & ~kSendEventMask) !=
- KeymapNotifyEvent::opcode) {
+ if (response_type != KeymapNotifyEvent::opcode) {
// On the wire, events are 32 bytes except for generic events which are
// trailed by additional data. XCB inserts an extended 4-byte sequence
// between the 32-byte event and the additional data, so we need to shift
// the additional data over by 4 bytes so the event is back in its wire
// format, which is what Xlib and XProto are expecting.
- if ((xcb_event->response_type & ~kSendEventMask) ==
- GeGenericEvent::opcode) {
+ if (response_type == GeGenericEvent::opcode) {
auto* ge = reinterpret_cast<xcb_ge_event_t*>(xcb_event);
constexpr size_t ge_length = sizeof(xcb_raw_generic_event_t);
constexpr size_t offset = sizeof(ge->full_sequence);
@@ -60,24 +60,24 @@
}
Event::Event(Event&& event) {
- memcpy(this, &event, sizeof(Event));
- memset(&event, 0, sizeof(Event));
+ operator=(std::move(event));
}
Event& Event::operator=(Event&& event) {
- Dealloc();
- memcpy(this, &event, sizeof(Event));
- memset(&event, 0, sizeof(Event));
+ // `window_` borrowed from `event_`, so it must be reset first.
+ window_ = std::move(event.window_);
+ event_ = std::move(event.event_);
+ type_id_ = event.type_id_;
+ sequence_ = event.sequence_;
+ send_event_ = event.send_event_;
+
+ // Clear the old instance, to make sure an invalid state isn't going to be
+ // used:
+ event.type_id_ = 0;
+ event.sequence_ = 0;
+ event.send_event_ = false;
return *this;
}
-Event::~Event() {
- Dealloc();
-}
-
-void Event::Dealloc() {
- if (deleter_)
- deleter_(event_);
-}
-
+Event::~Event() = default;
} // namespace x11
diff --git a/ui/gfx/x/event.h b/ui/gfx/x/event.h
index ed4f9b0..2652683 100644
--- a/ui/gfx/x/event.h
+++ b/ui/gfx/x/event.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,6 +9,7 @@
#include <utility>
#include "base/component_export.h"
+#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_refptr.h"
#include "ui/gfx/x/xproto.h"
@@ -25,13 +26,17 @@
class COMPONENT_EXPORT(X11) Event {
public:
template <typename T>
- explicit Event(T&& xproto_event) {
+ Event(bool send_event, T&& xproto_event) {
using DecayT = std::decay_t<T>;
+ send_event_ = send_event;
sequence_ = xproto_event.sequence;
type_id_ = DecayT::type_id;
- deleter_ = [](void* event) { delete reinterpret_cast<DecayT*>(event); };
auto* event = new DecayT(std::forward<T>(xproto_event));
- event_ = event;
+ event_ = {event, [](void* e) {
+ if (e) {
+ delete reinterpret_cast<DecayT*>(e);
+ }
+ }};
window_ = event->GetWindow();
}
@@ -53,7 +58,7 @@
template <typename T>
T* As() {
if (type_id_ == T::type_id)
- return reinterpret_cast<T*>(event_);
+ return reinterpret_cast<T*>(event_.get());
return nullptr;
}
@@ -62,6 +67,8 @@
return const_cast<Event*>(this)->As<T>();
}
+ bool send_event() const { return send_event_; }
+
uint32_t sequence() const { return sequence_; }
Window window() const { return window_ ? *window_ : Window::None; }
@@ -70,25 +77,25 @@
*window_ = window;
}
- bool Initialized() const { return deleter_; }
+ bool Initialized() const { return !!event_; }
private:
friend void ReadEvent(Event* event,
Connection* connection,
ReadBuffer* buffer);
- void Dealloc();
-
+ // True if this event was sent from another X client. False if this event
+ // was sent by the X server.
+ bool send_event_ = false;
uint16_t sequence_ = 0;
// XProto event state.
int type_id_ = 0;
- void (*deleter_)(void*) = nullptr;
- void* event_ = nullptr;
+ std::unique_ptr<void, void (*)(void*)> event_ = {nullptr, nullptr};
// This member points to a field in |event_|, or may be nullptr if there's no
// associated window for the event. It's owned by |event_|, not us.
- Window* window_ = nullptr;
+ raw_ptr<Window> window_ = nullptr;
};
} // namespace x11
diff --git a/ui/gfx/x/future.cc b/ui/gfx/x/future.cc
new file mode 100644
index 0000000..316d4ea
--- /dev/null
+++ b/ui/gfx/x/future.cc
@@ -0,0 +1,34 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/x/future.h"
+
+namespace x11 {
+
+FutureBase::FutureBase() = default;
+
+FutureBase::FutureBase(std::unique_ptr<Connection::FutureImpl> impl)
+ : impl_(std::move(impl)) {}
+
+FutureBase::FutureBase(FutureBase&&) = default;
+
+FutureBase& FutureBase::operator=(FutureBase&&) = default;
+
+FutureBase::~FutureBase() = default;
+
+void FutureBase::Wait() {
+ if (impl_)
+ impl_->Wait();
+}
+
+void FutureBase::DispatchNow() {
+ if (impl_)
+ impl_->DispatchNow();
+}
+
+bool FutureBase::AfterEvent(const Event& event) const {
+ return impl_ ? impl_->AfterEvent(event) : false;
+}
+
+} // namespace x11
\ No newline at end of file
diff --git a/ui/gfx/x/future.h b/ui/gfx/x/future.h
index fd20093..a61516c 100644
--- a/ui/gfx/x/future.h
+++ b/ui/gfx/x/future.h
@@ -1,36 +1,69 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_X_FUTURE_H_
#define UI_GFX_X_FUTURE_H_
+#include "base/component_export.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/xproto_types.h"
namespace x11 {
+class Event;
+
+class COMPONENT_EXPORT(X11) FutureBase {
+ public:
+ FutureBase();
+ explicit FutureBase(std::unique_ptr<Connection::FutureImpl> impl);
+ FutureBase(FutureBase&&);
+ FutureBase& operator=(FutureBase&&);
+ ~FutureBase();
+
+ // Block until this request is handled by the server.
+ void Wait();
+
+ // Block until this request is handled by the server. Unlike Sync(), this
+ // method doesn't return the response. Rather, it calls the response
+ // handler installed for this request out-of-order.
+ void DispatchNow();
+
+ // Returns true iff the response for this request was received after `event`.
+ bool AfterEvent(const Event& event) const;
+
+ protected:
+ Connection::FutureImpl* impl() { return impl_.get(); }
+
+ private:
+ std::unique_ptr<Connection::FutureImpl> impl_;
+};
+
// An Future wraps an asynchronous response from the X11 server. The
// response may be waited-for with Sync(), or asynchronously handled by
// installing a response handler using OnResponse().
template <typename Reply>
-class Future {
+class Future : public FutureBase {
public:
using Callback = base::OnceCallback<void(Response<Reply> response)>;
Future() = default;
explicit Future(std::unique_ptr<Connection::FutureImpl> impl)
- : impl_(std::move(impl)) {}
+ : FutureBase(std::move(impl)) {
+ static_assert(sizeof(Future<Reply>) == sizeof(FutureBase),
+ "Future must not have any members so that it can be sliced "
+ "to FutureBase");
+ }
// Blocks until we receive the response from the server. Returns the response.
Response<Reply> Sync() {
- if (!impl_)
+ if (!impl())
return {nullptr, nullptr};
Connection::RawReply raw_reply;
std::unique_ptr<Error> error;
- impl_->Sync(&raw_reply, &error);
+ impl()->Sync(&raw_reply, &error);
std::unique_ptr<Reply> reply;
if (raw_reply) {
@@ -41,17 +74,9 @@
return {std::move(reply), std::move(error)};
}
- // Block until this request is handled by the server. Unlike Sync(), this
- // method doesn't return the response. Rather, it calls the response
- // handler installed for this request out-of-order.
- void Wait() {
- if (impl_)
- impl_->Wait();
- }
-
// Installs |callback| to be run when the response is received.
void OnResponse(Callback callback) {
- if (!impl_)
+ if (!impl())
return;
// This intermediate callback handles the conversion from |raw_reply| to a
@@ -67,27 +92,24 @@
}
std::move(callback).Run({std::move(reply), std::move(error)});
};
- impl_->OnResponse(base::BindOnce(wrapper, std::move(callback)));
+ impl()->OnResponse(base::BindOnce(wrapper, std::move(callback)));
}
void IgnoreError() {
OnResponse(base::BindOnce([](Response<Reply>) {}));
}
-
- private:
- std::unique_ptr<Connection::FutureImpl> impl_;
};
// Sync() specialization for requests that don't generate replies. The returned
// response will only contain an error if there was one.
template <>
inline Response<void> Future<void>::Sync() {
- if (!impl_)
+ if (!impl())
return Response<void>{nullptr};
Connection::RawReply raw_reply;
std::unique_ptr<Error> error;
- impl_->Sync(&raw_reply, &error);
+ impl()->Sync(&raw_reply, &error);
DCHECK(!raw_reply);
return Response<void>(std::move(error));
}
@@ -96,7 +118,7 @@
// response argument to |callback| will only contain an error if there was one.
template <>
inline void Future<void>::OnResponse(Callback callback) {
- if (!impl_)
+ if (!impl())
return;
// See Future<Reply>::OnResponse() for an explanation of why
@@ -106,7 +128,7 @@
DCHECK(!reply);
std::move(callback).Run(Response<void>{std::move(error)});
};
- impl_->OnResponse(base::BindOnce(wrapper, std::move(callback)));
+ impl()->OnResponse(base::BindOnce(wrapper, std::move(callback)));
}
} // namespace x11
diff --git a/ui/gfx/x/gen_xproto.py b/ui/gfx/x/gen_xproto.py
index 715d80f..e5a7119 100644
--- a/ui/gfx/x/gen_xproto.py
+++ b/ui/gfx/x/gen_xproto.py
@@ -1,4 +1,4 @@
-# Copyright 2020 The Chromium Authors. All rights reserved.
+# Copyright 2020 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
@@ -84,7 +84,7 @@
])
FILE_HEADER = \
-'''// Copyright 2021 The Chromium Authors. All rights reserved.
+'''// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -262,11 +262,23 @@
# Enums that represent bit masks.
self.bitenums = []
- # Geenerate an ID suitable for use in temporary variable names.
+ # Generate an ID suitable for use in temporary variable names.
def new_uid(self, ):
self.prev_id += 1
return self.prev_id
+ def is_eq_comparable(self, type):
+ if type.is_list:
+ return self.is_eq_comparable(type.member)
+ if type.is_simple or type.is_pad:
+ return True
+ if (type.is_switch or type.is_union
+ or isinstance(type, self.xcbgen.xtypes.Request)
+ or isinstance(type, self.xcbgen.xtypes.Reply)):
+ return False
+ assert type.is_container
+ return all(self.is_eq_comparable(field.type) for field in type.fields)
+
def type_suffix(self, t):
if isinstance(t, self.xcbgen.xtypes.Error):
return 'Error'
@@ -730,8 +742,8 @@
# multiple windows. This is a list of all possible window names,
# ordered from highest to lowest priority.
WINDOW_NAMES = [
- 'event',
'window',
+ 'event',
'request_window',
'owner',
]
@@ -761,7 +773,6 @@
for (y, x) in event.enum_opcodes.items()]
for opcode, opname in sorted(items):
self.write('%s = %s,' % (opname, opcode))
- self.write('bool send_event{};')
self.declare_fields(event.fields)
self.write()
window_field = self.get_window_field(event)
@@ -779,8 +790,19 @@
self.write()
def declare_container(self, struct, struct_name):
- name = struct_name[-1] + self.type_suffix(struct)
- with Indent(self, 'struct %s {' % adjust_type_name(name), '};'):
+ name = adjust_type_name(struct_name[-1] + self.type_suffix(struct))
+ with Indent(self, 'struct %s {' % name, '};'):
+ if self.is_eq_comparable(struct):
+ sig = 'bool operator==(const %s& other) const {' % name
+ with Indent(self, sig, '}'):
+ terms = [
+ '%s == other.%s' % (field_name, field_name)
+ for field in struct.fields
+ for _, field_name in self.declare_field(field)
+ ]
+ expr = ' && '.join(terms) if terms else 'true'
+ self.write('return %s;' % expr)
+ self.write()
self.declare_fields(struct.fields)
self.write()
@@ -1311,6 +1333,7 @@
self.write_header()
self.write('#include "%s.h"' % self.module.namespace.header)
self.write()
+ self.write('#include <unistd.h>')
self.write('#include <xcb/xcb.h>')
self.write('#include <xcb/xcbext.h>')
self.write()
@@ -1483,15 +1506,15 @@
cond, opcode = self.event_condition(event, typename, proto)
with Indent(self, 'if (%s) {' % cond, '}'):
self.write('event->type_id_ = %d;' % event.type_id)
- with Indent(self, 'event->deleter_ = [](void* event) {', '};'):
- self.write('delete reinterpret_cast<%s*>(event);' % typename)
+ with Indent(self, 'auto deleter_ = [](void* e) {', '};'):
+ self.write('if(e){delete reinterpret_cast<%s*>(e);}' %
+ typename)
self.write('auto* event_ = new %s;' % typename)
self.write('ReadEvent(event_, buffer);')
if len(event.opcodes) > 1:
self.write('{0} = static_cast<decltype({0})>({1});'.format(
'event_->opcode', opcode))
- self.write('event_->send_event = send_event;')
- self.write('event->event_ = event_;')
+ self.write('event->event_ = {event_, deleter_};')
self.write('event->window_ = event_->GetWindow();')
self.write('return;')
self.write()
@@ -1518,11 +1541,10 @@
self.write(cast % ('ev', 'xcb_generic_event_t'))
self.write(cast % ('ge', 'xcb_ge_generic_event_t'))
self.write('auto evtype = ev->response_type & ~kSendEventMask;')
- self.write('bool send_event = ev->response_type & kSendEventMask;')
self.write()
for name, event, proto in self.events:
self.gen_event(name, event, proto)
- self.write('NOTREACHED();')
+ self.write('// Leave `event` default-initialized.')
self.write()
self.write('} // namespace x11')
diff --git a/ui/gfx/x/generated_protos/bigreq.cc b/ui/gfx/x/generated_protos/bigreq.cc
index 8ad0c82..89a7cfe 100644
--- a/ui/gfx/x/generated_protos/bigreq.cc
+++ b/ui/gfx/x/generated_protos/bigreq.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "bigreq.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/bigreq.h b/ui/gfx/x/generated_protos/bigreq.h
index 46d12de..84a6097 100644
--- a/ui/gfx/x/generated_protos/bigreq.h
+++ b/ui/gfx/x/generated_protos/bigreq.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -41,9 +41,11 @@
#ifndef UI_GFX_X_GENERATED_PROTOS_BIGREQ_H_
#define UI_GFX_X_GENERATED_PROTOS_BIGREQ_H_
+#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
+#include <vector>
#include "base/component_export.h"
#include "base/files/scoped_file.h"
diff --git a/ui/gfx/x/generated_protos/composite.cc b/ui/gfx/x/generated_protos/composite.cc
index 5fda723..0d2ca9a 100644
--- a/ui/gfx/x/generated_protos/composite.cc
+++ b/ui/gfx/x/generated_protos/composite.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "composite.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/composite.h b/ui/gfx/x/generated_protos/composite.h
index 76e8be6..3f56992 100644
--- a/ui/gfx/x/generated_protos/composite.h
+++ b/ui/gfx/x/generated_protos/composite.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/generated_protos/damage.cc b/ui/gfx/x/generated_protos/damage.cc
index bfd9c66..7900023 100644
--- a/ui/gfx/x/generated_protos/damage.cc
+++ b/ui/gfx/x/generated_protos/damage.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "damage.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
@@ -55,7 +56,10 @@
std::string Damage::BadDamageError::ToString() const {
std::stringstream ss_;
ss_ << "Damage::BadDamageError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -66,6 +70,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -78,6 +85,15 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
template <>
diff --git a/ui/gfx/x/generated_protos/damage.h b/ui/gfx/x/generated_protos/damage.h
index bcfd8c4..e541b9a 100644
--- a/ui/gfx/x/generated_protos/damage.h
+++ b/ui/gfx/x/generated_protos/damage.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -92,6 +92,9 @@
struct BadDamageError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
@@ -99,7 +102,6 @@
struct NotifyEvent {
static constexpr int type_id = 1;
static constexpr uint8_t opcode = 0;
- bool send_event{};
ReportLevel level{};
uint16_t sequence{};
Drawable drawable{};
diff --git a/ui/gfx/x/generated_protos/dpms.cc b/ui/gfx/x/generated_protos/dpms.cc
index dd007a3..0544f0d 100644
--- a/ui/gfx/x/generated_protos/dpms.cc
+++ b/ui/gfx/x/generated_protos/dpms.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "dpms.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/dpms.h b/ui/gfx/x/generated_protos/dpms.h
index f81f656..013f950 100644
--- a/ui/gfx/x/generated_protos/dpms.h
+++ b/ui/gfx/x/generated_protos/dpms.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/generated_protos/dri2.cc b/ui/gfx/x/generated_protos/dri2.cc
index 0e5eca2..804d256 100644
--- a/ui/gfx/x/generated_protos/dri2.cc
+++ b/ui/gfx/x/generated_protos/dri2.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "dri2.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/dri2.h b/ui/gfx/x/generated_protos/dri2.h
index 5d4a6bd..bef353b 100644
--- a/ui/gfx/x/generated_protos/dri2.h
+++ b/ui/gfx/x/generated_protos/dri2.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -106,6 +106,11 @@
};
struct DRI2Buffer {
+ bool operator==(const DRI2Buffer& other) const {
+ return attachment == other.attachment && name == other.name &&
+ pitch == other.pitch && cpp == other.cpp && flags == other.flags;
+ }
+
Attachment attachment{};
uint32_t name{};
uint32_t pitch{};
@@ -114,6 +119,10 @@
};
struct AttachFormat {
+ bool operator==(const AttachFormat& other) const {
+ return attachment == other.attachment && format == other.format;
+ }
+
Attachment attachment{};
uint32_t format{};
};
@@ -121,7 +130,6 @@
struct BufferSwapCompleteEvent {
static constexpr int type_id = 2;
static constexpr uint8_t opcode = 0;
- bool send_event{};
uint16_t sequence{};
EventType event_type{};
Drawable drawable{};
@@ -139,7 +147,6 @@
struct InvalidateBuffersEvent {
static constexpr int type_id = 3;
static constexpr uint8_t opcode = 1;
- bool send_event{};
uint16_t sequence{};
Drawable drawable{};
diff --git a/ui/gfx/x/generated_protos/dri3.cc b/ui/gfx/x/generated_protos/dri3.cc
index 158cfdf..22c9104 100644
--- a/ui/gfx/x/generated_protos/dri3.cc
+++ b/ui/gfx/x/generated_protos/dri3.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "dri3.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
@@ -852,4 +853,48 @@
return reply;
}
+Future<void> Dri3::SetDRMDeviceInUse(
+ const Dri3::SetDRMDeviceInUseRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& window = request.window;
+ auto& drmMajor = request.drmMajor;
+ auto& drmMinor = request.drmMinor;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 9;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // window
+ buf.Write(&window);
+
+ // drmMajor
+ buf.Write(&drmMajor);
+
+ // drmMinor
+ buf.Write(&drmMinor);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "Dri3::SetDRMDeviceInUse", false);
+}
+
+Future<void> Dri3::SetDRMDeviceInUse(const Window& window,
+ const uint32_t& drmMajor,
+ const uint32_t& drmMinor) {
+ return Dri3::SetDRMDeviceInUse(
+ Dri3::SetDRMDeviceInUseRequest{window, drmMajor, drmMinor});
+}
+
} // namespace x11
diff --git a/ui/gfx/x/generated_protos/dri3.h b/ui/gfx/x/generated_protos/dri3.h
index 9fda8e3..760b100 100644
--- a/ui/gfx/x/generated_protos/dri3.h
+++ b/ui/gfx/x/generated_protos/dri3.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -69,7 +69,7 @@
class COMPONENT_EXPORT(X11) Dri3 {
public:
static constexpr unsigned major_version = 1;
- static constexpr unsigned minor_version = 2;
+ static constexpr unsigned minor_version = 3;
Dri3(Connection* connection, const x11::QueryExtensionReply& info);
@@ -284,6 +284,20 @@
Future<BuffersFromPixmapReply> BuffersFromPixmap(const Pixmap& pixmap = {});
+ struct SetDRMDeviceInUseRequest {
+ Window window{};
+ uint32_t drmMajor{};
+ uint32_t drmMinor{};
+ };
+
+ using SetDRMDeviceInUseResponse = Response<void>;
+
+ Future<void> SetDRMDeviceInUse(const SetDRMDeviceInUseRequest& request);
+
+ Future<void> SetDRMDeviceInUse(const Window& window = {},
+ const uint32_t& drmMajor = {},
+ const uint32_t& drmMinor = {});
+
private:
Connection* const connection_;
x11::QueryExtensionReply info_{};
diff --git a/ui/gfx/x/generated_protos/extension_manager.cc b/ui/gfx/x/generated_protos/extension_manager.cc
index 5c680e8..36c1e6f 100644
--- a/ui/gfx/x/generated_protos/extension_manager.cc
+++ b/ui/gfx/x/generated_protos/extension_manager.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/generated_protos/extension_manager.h b/ui/gfx/x/generated_protos/extension_manager.h
index 625301a..74e511c 100644
--- a/ui/gfx/x/generated_protos/extension_manager.h
+++ b/ui/gfx/x/generated_protos/extension_manager.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/generated_protos/ge.cc b/ui/gfx/x/generated_protos/ge.cc
index 8afc628..f36e9f5 100644
--- a/ui/gfx/x/generated_protos/ge.cc
+++ b/ui/gfx/x/generated_protos/ge.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "ge.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/ge.h b/ui/gfx/x/generated_protos/ge.h
index 5e36176..dcb8519 100644
--- a/ui/gfx/x/generated_protos/ge.h
+++ b/ui/gfx/x/generated_protos/ge.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -41,9 +41,11 @@
#ifndef UI_GFX_X_GENERATED_PROTOS_GE_H_
#define UI_GFX_X_GENERATED_PROTOS_GE_H_
+#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
+#include <vector>
#include "base/component_export.h"
#include "base/files/scoped_file.h"
diff --git a/ui/gfx/x/generated_protos/glx.cc b/ui/gfx/x/generated_protos/glx.cc
index 3ae9c18..9526d2e 100644
--- a/ui/gfx/x/generated_protos/glx.cc
+++ b/ui/gfx/x/generated_protos/glx.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "glx.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
@@ -2796,6 +2797,9 @@
buf.Write(&gl_extension_string_elem);
}
+ // pad0
+ Align(&buf, 4);
+
// glx_extension_string
DCHECK_EQ(static_cast<size_t>(glx_str_len), glx_extension_string.size());
for (auto& glx_extension_string_elem : glx_extension_string) {
@@ -2955,6 +2959,9 @@
buf.Write(&gl_extension_string_elem);
}
+ // pad0
+ Align(&buf, 4);
+
// glx_extension_string
DCHECK_EQ(static_cast<size_t>(glx_str_len), glx_extension_string.size());
for (auto& glx_extension_string_elem : glx_extension_string) {
diff --git a/ui/gfx/x/generated_protos/glx.h b/ui/gfx/x/generated_protos/glx.h
index cc805bb..6550f56 100644
--- a/ui/gfx/x/generated_protos/glx.h
+++ b/ui/gfx/x/generated_protos/glx.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -290,7 +290,6 @@
struct PbufferClobberEvent {
static constexpr int type_id = 4;
static constexpr uint8_t opcode = 0;
- bool send_event{};
uint16_t sequence{};
uint16_t event_type{};
uint16_t draw_type{};
@@ -311,7 +310,6 @@
struct BufferSwapCompleteEvent {
static constexpr int type_id = 5;
static constexpr uint8_t opcode = 1;
- bool send_event{};
uint16_t sequence{};
uint16_t event_type{};
Drawable drawable{};
diff --git a/ui/gfx/x/generated_protos/present.cc b/ui/gfx/x/generated_protos/present.cc
index b4edda6..e3d886b 100644
--- a/ui/gfx/x/generated_protos/present.cc
+++ b/ui/gfx/x/generated_protos/present.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "present.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/present.h b/ui/gfx/x/generated_protos/present.h
index dcfd695..2231b02 100644
--- a/ui/gfx/x/generated_protos/present.h
+++ b/ui/gfx/x/generated_protos/present.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -126,6 +126,10 @@
};
struct Notify {
+ bool operator==(const Notify& other) const {
+ return window == other.window && serial == other.serial;
+ }
+
Window window{};
uint32_t serial{};
};
@@ -133,7 +137,6 @@
struct GenericEvent {
static constexpr int type_id = 6;
static constexpr uint8_t opcode = 0;
- bool send_event{};
uint8_t extension{};
uint16_t sequence{};
uint32_t length{};
@@ -146,7 +149,6 @@
struct ConfigureNotifyEvent {
static constexpr int type_id = 7;
static constexpr uint8_t opcode = 0;
- bool send_event{};
uint16_t sequence{};
Event event{};
Window window{};
@@ -166,7 +168,6 @@
struct CompleteNotifyEvent {
static constexpr int type_id = 8;
static constexpr uint8_t opcode = 1;
- bool send_event{};
uint16_t sequence{};
CompleteKind kind{};
CompleteMode mode{};
@@ -182,7 +183,6 @@
struct IdleNotifyEvent {
static constexpr int type_id = 9;
static constexpr uint8_t opcode = 2;
- bool send_event{};
uint16_t sequence{};
Event event{};
Window window{};
@@ -196,7 +196,6 @@
struct RedirectNotifyEvent {
static constexpr int type_id = 10;
static constexpr uint8_t opcode = 3;
- bool send_event{};
uint16_t sequence{};
uint8_t update_window{};
Event event{};
diff --git a/ui/gfx/x/generated_protos/randr.cc b/ui/gfx/x/generated_protos/randr.cc
index 7228c86..a2e8af9 100644
--- a/ui/gfx/x/generated_protos/randr.cc
+++ b/ui/gfx/x/generated_protos/randr.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "randr.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
@@ -55,7 +56,10 @@
std::string RandR::BadOutputError::ToString() const {
std::stringstream ss_;
ss_ << "RandR::BadOutputError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -66,6 +70,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -78,12 +85,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string RandR::BadCrtcError::ToString() const {
std::stringstream ss_;
ss_ << "RandR::BadCrtcError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -94,6 +113,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -106,12 +128,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string RandR::BadModeError::ToString() const {
std::stringstream ss_;
ss_ << "RandR::BadModeError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -122,6 +156,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -134,12 +171,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string RandR::BadProviderError::ToString() const {
std::stringstream ss_;
ss_ << "RandR::BadProviderError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -150,6 +199,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -162,6 +214,15 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
template <>
@@ -2494,7 +2555,7 @@
buf.Write(&crtc);
// size
- size = red.size();
+ size = blue.size();
buf.Write(&size);
// pad0
diff --git a/ui/gfx/x/generated_protos/randr.h b/ui/gfx/x/generated_protos/randr.h
index 1f420bb..fa8f362 100644
--- a/ui/gfx/x/generated_protos/randr.h
+++ b/ui/gfx/x/generated_protos/randr.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -167,29 +167,46 @@
struct BadOutputError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct BadCrtcError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct BadModeError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct BadProviderError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct ScreenSize {
+ bool operator==(const ScreenSize& other) const {
+ return width == other.width && height == other.height &&
+ mwidth == other.mwidth && mheight == other.mheight;
+ }
+
uint16_t width{};
uint16_t height{};
uint16_t mwidth{};
@@ -197,10 +214,23 @@
};
struct RefreshRates {
+ bool operator==(const RefreshRates& other) const {
+ return rates == other.rates;
+ }
+
std::vector<uint16_t> rates{};
};
struct ModeInfo {
+ bool operator==(const ModeInfo& other) const {
+ return id == other.id && width == other.width && height == other.height &&
+ dot_clock == other.dot_clock && hsync_start == other.hsync_start &&
+ hsync_end == other.hsync_end && htotal == other.htotal &&
+ hskew == other.hskew && vsync_start == other.vsync_start &&
+ vsync_end == other.vsync_end && vtotal == other.vtotal &&
+ name_len == other.name_len && mode_flags == other.mode_flags;
+ }
+
uint32_t id{};
uint16_t width{};
uint16_t height{};
@@ -219,7 +249,6 @@
struct ScreenChangeNotifyEvent {
static constexpr int type_id = 11;
static constexpr uint8_t opcode = 0;
- bool send_event{};
Rotation rotation{};
uint16_t sequence{};
Time timestamp{};
@@ -239,6 +268,15 @@
};
struct MonitorInfo {
+ bool operator==(const MonitorInfo& other) const {
+ return name == other.name && primary == other.primary &&
+ automatic == other.automatic && x == other.x && y == other.y &&
+ width == other.width && height == other.height &&
+ width_in_millimeters == other.width_in_millimeters &&
+ height_in_millimeters == other.height_in_millimeters &&
+ outputs == other.outputs;
+ }
+
Atom name{};
uint8_t primary{};
uint8_t automatic{};
@@ -254,7 +292,6 @@
struct NotifyEvent {
static constexpr int type_id = 12;
static constexpr uint8_t opcode = 1;
- bool send_event{};
uint16_t sequence{};
struct Cc {
Time timestamp{};
diff --git a/ui/gfx/x/generated_protos/read_error.cc b/ui/gfx/x/generated_protos/read_error.cc
index 1414180..7b7d930 100644
--- a/ui/gfx/x/generated_protos/read_error.cc
+++ b/ui/gfx/x/generated_protos/read_error.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/generated_protos/read_event.cc b/ui/gfx/x/generated_protos/read_event.cc
index a6a308f..8b7466d 100644
--- a/ui/gfx/x/generated_protos/read_event.cc
+++ b/ui/gfx/x/generated_protos/read_event.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -83,18 +83,18 @@
auto* ev = reinterpret_cast<const xcb_generic_event_t*>(buf);
auto* ge = reinterpret_cast<const xcb_ge_generic_event_t*>(buf);
auto evtype = ev->response_type & ~kSendEventMask;
- bool send_event = ev->response_type & kSendEventMask;
if (conn->damage().present() &&
evtype - conn->damage().first_event() == Damage::NotifyEvent::opcode) {
event->type_id_ = 1;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Damage::NotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Damage::NotifyEvent*>(e);
+ }
};
auto* event_ = new Damage::NotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -102,13 +102,14 @@
if (conn->dri2().present() && evtype - conn->dri2().first_event() ==
Dri2::BufferSwapCompleteEvent::opcode) {
event->type_id_ = 2;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Dri2::BufferSwapCompleteEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Dri2::BufferSwapCompleteEvent*>(e);
+ }
};
auto* event_ = new Dri2::BufferSwapCompleteEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -116,13 +117,14 @@
if (conn->dri2().present() && evtype - conn->dri2().first_event() ==
Dri2::InvalidateBuffersEvent::opcode) {
event->type_id_ = 3;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Dri2::InvalidateBuffersEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Dri2::InvalidateBuffersEvent*>(e);
+ }
};
auto* event_ = new Dri2::InvalidateBuffersEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -130,13 +132,14 @@
if (conn->glx().present() &&
evtype - conn->glx().first_event() == Glx::PbufferClobberEvent::opcode) {
event->type_id_ = 4;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Glx::PbufferClobberEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Glx::PbufferClobberEvent*>(e);
+ }
};
auto* event_ = new Glx::PbufferClobberEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -144,13 +147,14 @@
if (conn->glx().present() && evtype - conn->glx().first_event() ==
Glx::BufferSwapCompleteEvent::opcode) {
event->type_id_ = 5;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Glx::BufferSwapCompleteEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Glx::BufferSwapCompleteEvent*>(e);
+ }
};
auto* event_ = new Glx::BufferSwapCompleteEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -158,13 +162,14 @@
if (conn->present().present() &&
evtype - conn->present().first_event() == Present::GenericEvent::opcode) {
event->type_id_ = 6;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Present::GenericEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Present::GenericEvent*>(e);
+ }
};
auto* event_ = new Present::GenericEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -173,13 +178,14 @@
ge->extension == conn->present().major_opcode() &&
ge->event_type == Present::ConfigureNotifyEvent::opcode) {
event->type_id_ = 7;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Present::ConfigureNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Present::ConfigureNotifyEvent*>(e);
+ }
};
auto* event_ = new Present::ConfigureNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -188,13 +194,14 @@
ge->extension == conn->present().major_opcode() &&
ge->event_type == Present::CompleteNotifyEvent::opcode) {
event->type_id_ = 8;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Present::CompleteNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Present::CompleteNotifyEvent*>(e);
+ }
};
auto* event_ = new Present::CompleteNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -203,13 +210,14 @@
ge->extension == conn->present().major_opcode() &&
ge->event_type == Present::IdleNotifyEvent::opcode) {
event->type_id_ = 9;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Present::IdleNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Present::IdleNotifyEvent*>(e);
+ }
};
auto* event_ = new Present::IdleNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -218,13 +226,14 @@
ge->extension == conn->present().major_opcode() &&
ge->event_type == Present::RedirectNotifyEvent::opcode) {
event->type_id_ = 10;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Present::RedirectNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Present::RedirectNotifyEvent*>(e);
+ }
};
auto* event_ = new Present::RedirectNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -232,13 +241,14 @@
if (conn->randr().present() && evtype - conn->randr().first_event() ==
RandR::ScreenChangeNotifyEvent::opcode) {
event->type_id_ = 11;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<RandR::ScreenChangeNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<RandR::ScreenChangeNotifyEvent*>(e);
+ }
};
auto* event_ = new RandR::ScreenChangeNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -246,13 +256,14 @@
if (conn->randr().present() &&
evtype - conn->randr().first_event() == RandR::NotifyEvent::opcode) {
event->type_id_ = 12;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<RandR::NotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<RandR::NotifyEvent*>(e);
+ }
};
auto* event_ = new RandR::NotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -261,13 +272,14 @@
evtype - conn->screensaver().first_event() ==
ScreenSaver::NotifyEvent::opcode) {
event->type_id_ = 13;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<ScreenSaver::NotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<ScreenSaver::NotifyEvent*>(e);
+ }
};
auto* event_ = new ScreenSaver::NotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -275,13 +287,14 @@
if (conn->shape().present() &&
evtype - conn->shape().first_event() == Shape::NotifyEvent::opcode) {
event->type_id_ = 14;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Shape::NotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Shape::NotifyEvent*>(e);
+ }
};
auto* event_ = new Shape::NotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -289,13 +302,14 @@
if (conn->shm().present() &&
evtype - conn->shm().first_event() == Shm::CompletionEvent::opcode) {
event->type_id_ = 15;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Shm::CompletionEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Shm::CompletionEvent*>(e);
+ }
};
auto* event_ = new Shm::CompletionEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -303,13 +317,14 @@
if (conn->sync().present() &&
evtype - conn->sync().first_event() == Sync::CounterNotifyEvent::opcode) {
event->type_id_ = 16;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Sync::CounterNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Sync::CounterNotifyEvent*>(e);
+ }
};
auto* event_ = new Sync::CounterNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -317,13 +332,14 @@
if (conn->sync().present() &&
evtype - conn->sync().first_event() == Sync::AlarmNotifyEvent::opcode) {
event->type_id_ = 17;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Sync::AlarmNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Sync::AlarmNotifyEvent*>(e);
+ }
};
auto* event_ = new Sync::AlarmNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -331,13 +347,14 @@
if (conn->xfixes().present() && evtype - conn->xfixes().first_event() ==
XFixes::SelectionNotifyEvent::opcode) {
event->type_id_ = 18;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<XFixes::SelectionNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<XFixes::SelectionNotifyEvent*>(e);
+ }
};
auto* event_ = new XFixes::SelectionNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -345,13 +362,14 @@
if (conn->xfixes().present() && evtype - conn->xfixes().first_event() ==
XFixes::CursorNotifyEvent::opcode) {
event->type_id_ = 19;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<XFixes::CursorNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<XFixes::CursorNotifyEvent*>(e);
+ }
};
auto* event_ = new XFixes::CursorNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -359,42 +377,44 @@
if (conn->xinput().present() && evtype - conn->xinput().first_event() ==
Input::DeviceValuatorEvent::opcode) {
event->type_id_ = 20;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::DeviceValuatorEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::DeviceValuatorEvent*>(e);
+ }
};
auto* event_ = new Input::DeviceValuatorEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xinput().present() &&
(evtype - conn->xinput().first_event() ==
- Input::LegacyDeviceEvent::DeviceButtonRelease ||
- evtype - conn->xinput().first_event() ==
- Input::LegacyDeviceEvent::ProximityIn ||
+ Input::LegacyDeviceEvent::DeviceKeyPress ||
evtype - conn->xinput().first_event() ==
Input::LegacyDeviceEvent::DeviceKeyRelease ||
evtype - conn->xinput().first_event() ==
Input::LegacyDeviceEvent::DeviceButtonPress ||
evtype - conn->xinput().first_event() ==
- Input::LegacyDeviceEvent::ProximityOut ||
+ Input::LegacyDeviceEvent::DeviceButtonRelease ||
evtype - conn->xinput().first_event() ==
- Input::LegacyDeviceEvent::DeviceKeyPress ||
+ Input::LegacyDeviceEvent::DeviceMotionNotify ||
evtype - conn->xinput().first_event() ==
- Input::LegacyDeviceEvent::DeviceMotionNotify)) {
+ Input::LegacyDeviceEvent::ProximityIn ||
+ evtype - conn->xinput().first_event() ==
+ Input::LegacyDeviceEvent::ProximityOut)) {
event->type_id_ = 21;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::LegacyDeviceEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::LegacyDeviceEvent*>(e);
+ }
};
auto* event_ = new Input::LegacyDeviceEvent;
ReadEvent(event_, buffer);
event_->opcode = static_cast<decltype(event_->opcode)>(
evtype - conn->xinput().first_event());
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -403,15 +423,16 @@
(evtype - conn->xinput().first_event() == Input::DeviceFocusEvent::In ||
evtype - conn->xinput().first_event() == Input::DeviceFocusEvent::Out)) {
event->type_id_ = 22;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::DeviceFocusEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::DeviceFocusEvent*>(e);
+ }
};
auto* event_ = new Input::DeviceFocusEvent;
ReadEvent(event_, buffer);
event_->opcode = static_cast<decltype(event_->opcode)>(
evtype - conn->xinput().first_event());
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -419,13 +440,14 @@
if (conn->xinput().present() && evtype - conn->xinput().first_event() ==
Input::DeviceStateNotifyEvent::opcode) {
event->type_id_ = 23;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::DeviceStateNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::DeviceStateNotifyEvent*>(e);
+ }
};
auto* event_ = new Input::DeviceStateNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -433,13 +455,14 @@
if (conn->xinput().present() && evtype - conn->xinput().first_event() ==
Input::DeviceMappingNotifyEvent::opcode) {
event->type_id_ = 24;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::DeviceMappingNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::DeviceMappingNotifyEvent*>(e);
+ }
};
auto* event_ = new Input::DeviceMappingNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -447,13 +470,14 @@
if (conn->xinput().present() && evtype - conn->xinput().first_event() ==
Input::ChangeDeviceNotifyEvent::opcode) {
event->type_id_ = 25;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::ChangeDeviceNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::ChangeDeviceNotifyEvent*>(e);
+ }
};
auto* event_ = new Input::ChangeDeviceNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -462,13 +486,14 @@
evtype - conn->xinput().first_event() ==
Input::DeviceKeyStateNotifyEvent::opcode) {
event->type_id_ = 26;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::DeviceKeyStateNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::DeviceKeyStateNotifyEvent*>(e);
+ }
};
auto* event_ = new Input::DeviceKeyStateNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -477,13 +502,14 @@
evtype - conn->xinput().first_event() ==
Input::DeviceButtonStateNotifyEvent::opcode) {
event->type_id_ = 27;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::DeviceButtonStateNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::DeviceButtonStateNotifyEvent*>(e);
+ }
};
auto* event_ = new Input::DeviceButtonStateNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -492,13 +518,14 @@
evtype - conn->xinput().first_event() ==
Input::DevicePresenceNotifyEvent::opcode) {
event->type_id_ = 28;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::DevicePresenceNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::DevicePresenceNotifyEvent*>(e);
+ }
};
auto* event_ = new Input::DevicePresenceNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -507,13 +534,14 @@
evtype - conn->xinput().first_event() ==
Input::DevicePropertyNotifyEvent::opcode) {
event->type_id_ = 29;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::DevicePropertyNotifyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::DevicePropertyNotifyEvent*>(e);
+ }
};
auto* event_ = new Input::DevicePropertyNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -522,55 +550,58 @@
ge->extension == conn->xinput().major_opcode() &&
ge->event_type == Input::DeviceChangedEvent::opcode) {
event->type_id_ = 30;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::DeviceChangedEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::DeviceChangedEvent*>(e);
+ }
};
auto* event_ = new Input::DeviceChangedEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == GeGenericEvent::opcode && conn->xinput().present() &&
ge->extension == conn->xinput().major_opcode() &&
- (ge->event_type == Input::DeviceEvent::ButtonPress ||
- ge->event_type == Input::DeviceEvent::TouchEnd ||
+ (ge->event_type == Input::DeviceEvent::KeyPress ||
ge->event_type == Input::DeviceEvent::KeyRelease ||
- ge->event_type == Input::DeviceEvent::TouchUpdate ||
- ge->event_type == Input::DeviceEvent::KeyPress ||
+ ge->event_type == Input::DeviceEvent::ButtonPress ||
+ ge->event_type == Input::DeviceEvent::ButtonRelease ||
ge->event_type == Input::DeviceEvent::Motion ||
ge->event_type == Input::DeviceEvent::TouchBegin ||
- ge->event_type == Input::DeviceEvent::ButtonRelease)) {
+ ge->event_type == Input::DeviceEvent::TouchUpdate ||
+ ge->event_type == Input::DeviceEvent::TouchEnd)) {
event->type_id_ = 31;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::DeviceEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::DeviceEvent*>(e);
+ }
};
auto* event_ = new Input::DeviceEvent;
ReadEvent(event_, buffer);
event_->opcode = static_cast<decltype(event_->opcode)>(ge->event_type);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == GeGenericEvent::opcode && conn->xinput().present() &&
ge->extension == conn->xinput().major_opcode() &&
- (ge->event_type == Input::CrossingEvent::Leave ||
+ (ge->event_type == Input::CrossingEvent::Enter ||
+ ge->event_type == Input::CrossingEvent::Leave ||
ge->event_type == Input::CrossingEvent::FocusIn ||
- ge->event_type == Input::CrossingEvent::FocusOut ||
- ge->event_type == Input::CrossingEvent::Enter)) {
+ ge->event_type == Input::CrossingEvent::FocusOut)) {
event->type_id_ = 32;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::CrossingEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::CrossingEvent*>(e);
+ }
};
auto* event_ = new Input::CrossingEvent;
ReadEvent(event_, buffer);
event_->opcode = static_cast<decltype(event_->opcode)>(ge->event_type);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -579,13 +610,14 @@
ge->extension == conn->xinput().major_opcode() &&
ge->event_type == Input::HierarchyEvent::opcode) {
event->type_id_ = 33;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::HierarchyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::HierarchyEvent*>(e);
+ }
};
auto* event_ = new Input::HierarchyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -594,36 +626,38 @@
ge->extension == conn->xinput().major_opcode() &&
ge->event_type == Input::PropertyEvent::opcode) {
event->type_id_ = 34;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::PropertyEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::PropertyEvent*>(e);
+ }
};
auto* event_ = new Input::PropertyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == GeGenericEvent::opcode && conn->xinput().present() &&
ge->extension == conn->xinput().major_opcode() &&
- (ge->event_type == Input::RawDeviceEvent::RawTouchEnd ||
- ge->event_type == Input::RawDeviceEvent::RawTouchUpdate ||
- ge->event_type == Input::RawDeviceEvent::RawTouchBegin ||
+ (ge->event_type == Input::RawDeviceEvent::RawKeyPress ||
+ ge->event_type == Input::RawDeviceEvent::RawKeyRelease ||
+ ge->event_type == Input::RawDeviceEvent::RawButtonPress ||
ge->event_type == Input::RawDeviceEvent::RawButtonRelease ||
ge->event_type == Input::RawDeviceEvent::RawMotion ||
- ge->event_type == Input::RawDeviceEvent::RawButtonPress ||
- ge->event_type == Input::RawDeviceEvent::RawKeyRelease ||
- ge->event_type == Input::RawDeviceEvent::RawKeyPress)) {
+ ge->event_type == Input::RawDeviceEvent::RawTouchBegin ||
+ ge->event_type == Input::RawDeviceEvent::RawTouchUpdate ||
+ ge->event_type == Input::RawDeviceEvent::RawTouchEnd)) {
event->type_id_ = 35;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::RawDeviceEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::RawDeviceEvent*>(e);
+ }
};
auto* event_ = new Input::RawDeviceEvent;
ReadEvent(event_, buffer);
event_->opcode = static_cast<decltype(event_->opcode)>(ge->event_type);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
@@ -632,629 +666,713 @@
ge->extension == conn->xinput().major_opcode() &&
ge->event_type == Input::TouchOwnershipEvent::opcode) {
event->type_id_ = 36;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::TouchOwnershipEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::TouchOwnershipEvent*>(e);
+ }
};
auto* event_ = new Input::TouchOwnershipEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == GeGenericEvent::opcode && conn->xinput().present() &&
ge->extension == conn->xinput().major_opcode() &&
- (ge->event_type == Input::BarrierEvent::Leave ||
- ge->event_type == Input::BarrierEvent::Hit)) {
+ (ge->event_type == Input::BarrierEvent::Hit ||
+ ge->event_type == Input::BarrierEvent::Leave)) {
event->type_id_ = 37;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Input::BarrierEvent*>(event);
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::BarrierEvent*>(e);
+ }
};
auto* event_ = new Input::BarrierEvent;
ReadEvent(event_, buffer);
event_->opcode = static_cast<decltype(event_->opcode)>(ge->event_type);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GeGenericEvent::opcode && conn->xinput().present() &&
+ ge->extension == conn->xinput().major_opcode() &&
+ (ge->event_type == Input::GesturePinchEvent::Begin ||
+ ge->event_type == Input::GesturePinchEvent::Update ||
+ ge->event_type == Input::GesturePinchEvent::End)) {
+ event->type_id_ = 38;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::GesturePinchEvent*>(e);
+ }
+ };
+ auto* event_ = new Input::GesturePinchEvent;
+ ReadEvent(event_, buffer);
+ event_->opcode = static_cast<decltype(event_->opcode)>(ge->event_type);
+ event->event_ = {event_, deleter_};
+ event->window_ = event_->GetWindow();
+ return;
+ }
+
+ if (evtype == GeGenericEvent::opcode && conn->xinput().present() &&
+ ge->extension == conn->xinput().major_opcode() &&
+ (ge->event_type == Input::GestureSwipeEvent::Begin ||
+ ge->event_type == Input::GestureSwipeEvent::Update ||
+ ge->event_type == Input::GestureSwipeEvent::End)) {
+ event->type_id_ = 39;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Input::GestureSwipeEvent*>(e);
+ }
+ };
+ auto* event_ = new Input::GestureSwipeEvent;
+ ReadEvent(event_, buffer);
+ event_->opcode = static_cast<decltype(event_->opcode)>(ge->event_type);
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xkb().present() && evtype - conn->xkb().first_event() ==
Xkb::NewKeyboardNotifyEvent::opcode) {
- event->type_id_ = 38;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Xkb::NewKeyboardNotifyEvent*>(event);
+ event->type_id_ = 40;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Xkb::NewKeyboardNotifyEvent*>(e);
+ }
};
auto* event_ = new Xkb::NewKeyboardNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xkb().present() &&
evtype - conn->xkb().first_event() == Xkb::MapNotifyEvent::opcode) {
- event->type_id_ = 39;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Xkb::MapNotifyEvent*>(event);
+ event->type_id_ = 41;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Xkb::MapNotifyEvent*>(e);
+ }
};
auto* event_ = new Xkb::MapNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xkb().present() &&
evtype - conn->xkb().first_event() == Xkb::StateNotifyEvent::opcode) {
- event->type_id_ = 40;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Xkb::StateNotifyEvent*>(event);
+ event->type_id_ = 42;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Xkb::StateNotifyEvent*>(e);
+ }
};
auto* event_ = new Xkb::StateNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xkb().present() &&
evtype - conn->xkb().first_event() == Xkb::ControlsNotifyEvent::opcode) {
- event->type_id_ = 41;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Xkb::ControlsNotifyEvent*>(event);
+ event->type_id_ = 43;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Xkb::ControlsNotifyEvent*>(e);
+ }
};
auto* event_ = new Xkb::ControlsNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xkb().present() && evtype - conn->xkb().first_event() ==
Xkb::IndicatorStateNotifyEvent::opcode) {
- event->type_id_ = 42;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Xkb::IndicatorStateNotifyEvent*>(event);
+ event->type_id_ = 44;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Xkb::IndicatorStateNotifyEvent*>(e);
+ }
};
auto* event_ = new Xkb::IndicatorStateNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xkb().present() && evtype - conn->xkb().first_event() ==
Xkb::IndicatorMapNotifyEvent::opcode) {
- event->type_id_ = 43;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Xkb::IndicatorMapNotifyEvent*>(event);
+ event->type_id_ = 45;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Xkb::IndicatorMapNotifyEvent*>(e);
+ }
};
auto* event_ = new Xkb::IndicatorMapNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xkb().present() &&
evtype - conn->xkb().first_event() == Xkb::NamesNotifyEvent::opcode) {
- event->type_id_ = 44;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Xkb::NamesNotifyEvent*>(event);
+ event->type_id_ = 46;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Xkb::NamesNotifyEvent*>(e);
+ }
};
auto* event_ = new Xkb::NamesNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xkb().present() &&
evtype - conn->xkb().first_event() == Xkb::CompatMapNotifyEvent::opcode) {
- event->type_id_ = 45;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Xkb::CompatMapNotifyEvent*>(event);
+ event->type_id_ = 47;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Xkb::CompatMapNotifyEvent*>(e);
+ }
};
auto* event_ = new Xkb::CompatMapNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xkb().present() &&
evtype - conn->xkb().first_event() == Xkb::BellNotifyEvent::opcode) {
- event->type_id_ = 46;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Xkb::BellNotifyEvent*>(event);
+ event->type_id_ = 48;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Xkb::BellNotifyEvent*>(e);
+ }
};
auto* event_ = new Xkb::BellNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xkb().present() &&
evtype - conn->xkb().first_event() == Xkb::ActionMessageEvent::opcode) {
- event->type_id_ = 47;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Xkb::ActionMessageEvent*>(event);
+ event->type_id_ = 49;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Xkb::ActionMessageEvent*>(e);
+ }
};
auto* event_ = new Xkb::ActionMessageEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xkb().present() &&
evtype - conn->xkb().first_event() == Xkb::AccessXNotifyEvent::opcode) {
- event->type_id_ = 48;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Xkb::AccessXNotifyEvent*>(event);
+ event->type_id_ = 50;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Xkb::AccessXNotifyEvent*>(e);
+ }
};
auto* event_ = new Xkb::AccessXNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xkb().present() && evtype - conn->xkb().first_event() ==
Xkb::ExtensionDeviceNotifyEvent::opcode) {
- event->type_id_ = 49;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Xkb::ExtensionDeviceNotifyEvent*>(event);
+ event->type_id_ = 51;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Xkb::ExtensionDeviceNotifyEvent*>(e);
+ }
};
auto* event_ = new Xkb::ExtensionDeviceNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xprint().present() &&
evtype - conn->xprint().first_event() == XPrint::NotifyEvent::opcode) {
- event->type_id_ = 50;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<XPrint::NotifyEvent*>(event);
+ event->type_id_ = 52;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<XPrint::NotifyEvent*>(e);
+ }
};
auto* event_ = new XPrint::NotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xprint().present() && evtype - conn->xprint().first_event() ==
XPrint::AttributNotifyEvent::opcode) {
- event->type_id_ = 51;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<XPrint::AttributNotifyEvent*>(event);
+ event->type_id_ = 53;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<XPrint::AttributNotifyEvent*>(e);
+ }
};
auto* event_ = new XPrint::AttributNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
- if ((evtype == KeyEvent::Release || evtype == KeyEvent::Press)) {
- event->type_id_ = 52;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<KeyEvent*>(event);
+ if ((evtype == KeyEvent::Press || evtype == KeyEvent::Release)) {
+ event->type_id_ = 54;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<KeyEvent*>(e);
+ }
};
auto* event_ = new KeyEvent;
ReadEvent(event_, buffer);
event_->opcode = static_cast<decltype(event_->opcode)>(evtype);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
- if ((evtype == ButtonEvent::Release || evtype == ButtonEvent::Press)) {
- event->type_id_ = 53;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<ButtonEvent*>(event);
+ if ((evtype == ButtonEvent::Press || evtype == ButtonEvent::Release)) {
+ event->type_id_ = 55;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<ButtonEvent*>(e);
+ }
};
auto* event_ = new ButtonEvent;
ReadEvent(event_, buffer);
event_->opcode = static_cast<decltype(event_->opcode)>(evtype);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == MotionNotifyEvent::opcode) {
- event->type_id_ = 54;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<MotionNotifyEvent*>(event);
+ event->type_id_ = 56;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<MotionNotifyEvent*>(e);
+ }
};
auto* event_ = new MotionNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if ((evtype == CrossingEvent::EnterNotify ||
evtype == CrossingEvent::LeaveNotify)) {
- event->type_id_ = 55;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<CrossingEvent*>(event);
+ event->type_id_ = 57;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<CrossingEvent*>(e);
+ }
};
auto* event_ = new CrossingEvent;
ReadEvent(event_, buffer);
event_->opcode = static_cast<decltype(event_->opcode)>(evtype);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
- if ((evtype == FocusEvent::Out || evtype == FocusEvent::In)) {
- event->type_id_ = 56;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<FocusEvent*>(event);
+ if ((evtype == FocusEvent::In || evtype == FocusEvent::Out)) {
+ event->type_id_ = 58;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<FocusEvent*>(e);
+ }
};
auto* event_ = new FocusEvent;
ReadEvent(event_, buffer);
event_->opcode = static_cast<decltype(event_->opcode)>(evtype);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == KeymapNotifyEvent::opcode) {
- event->type_id_ = 57;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<KeymapNotifyEvent*>(event);
+ event->type_id_ = 59;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<KeymapNotifyEvent*>(e);
+ }
};
auto* event_ = new KeymapNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == ExposeEvent::opcode) {
- event->type_id_ = 58;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<ExposeEvent*>(event);
+ event->type_id_ = 60;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<ExposeEvent*>(e);
+ }
};
auto* event_ = new ExposeEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == GraphicsExposureEvent::opcode) {
- event->type_id_ = 59;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<GraphicsExposureEvent*>(event);
+ event->type_id_ = 61;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<GraphicsExposureEvent*>(e);
+ }
};
auto* event_ = new GraphicsExposureEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == NoExposureEvent::opcode) {
- event->type_id_ = 60;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<NoExposureEvent*>(event);
+ event->type_id_ = 62;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<NoExposureEvent*>(e);
+ }
};
auto* event_ = new NoExposureEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == VisibilityNotifyEvent::opcode) {
- event->type_id_ = 61;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<VisibilityNotifyEvent*>(event);
+ event->type_id_ = 63;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<VisibilityNotifyEvent*>(e);
+ }
};
auto* event_ = new VisibilityNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == CreateNotifyEvent::opcode) {
- event->type_id_ = 62;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<CreateNotifyEvent*>(event);
+ event->type_id_ = 64;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<CreateNotifyEvent*>(e);
+ }
};
auto* event_ = new CreateNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == DestroyNotifyEvent::opcode) {
- event->type_id_ = 63;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<DestroyNotifyEvent*>(event);
+ event->type_id_ = 65;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<DestroyNotifyEvent*>(e);
+ }
};
auto* event_ = new DestroyNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == UnmapNotifyEvent::opcode) {
- event->type_id_ = 64;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<UnmapNotifyEvent*>(event);
+ event->type_id_ = 66;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<UnmapNotifyEvent*>(e);
+ }
};
auto* event_ = new UnmapNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == MapNotifyEvent::opcode) {
- event->type_id_ = 65;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<MapNotifyEvent*>(event);
+ event->type_id_ = 67;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<MapNotifyEvent*>(e);
+ }
};
auto* event_ = new MapNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == MapRequestEvent::opcode) {
- event->type_id_ = 66;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<MapRequestEvent*>(event);
+ event->type_id_ = 68;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<MapRequestEvent*>(e);
+ }
};
auto* event_ = new MapRequestEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == ReparentNotifyEvent::opcode) {
- event->type_id_ = 67;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<ReparentNotifyEvent*>(event);
+ event->type_id_ = 69;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<ReparentNotifyEvent*>(e);
+ }
};
auto* event_ = new ReparentNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == ConfigureNotifyEvent::opcode) {
- event->type_id_ = 68;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<ConfigureNotifyEvent*>(event);
+ event->type_id_ = 70;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<ConfigureNotifyEvent*>(e);
+ }
};
auto* event_ = new ConfigureNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == ConfigureRequestEvent::opcode) {
- event->type_id_ = 69;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<ConfigureRequestEvent*>(event);
+ event->type_id_ = 71;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<ConfigureRequestEvent*>(e);
+ }
};
auto* event_ = new ConfigureRequestEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == GravityNotifyEvent::opcode) {
- event->type_id_ = 70;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<GravityNotifyEvent*>(event);
+ event->type_id_ = 72;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<GravityNotifyEvent*>(e);
+ }
};
auto* event_ = new GravityNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == ResizeRequestEvent::opcode) {
- event->type_id_ = 71;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<ResizeRequestEvent*>(event);
+ event->type_id_ = 73;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<ResizeRequestEvent*>(e);
+ }
};
auto* event_ = new ResizeRequestEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
- if ((evtype == CirculateEvent::Request || evtype == CirculateEvent::Notify)) {
- event->type_id_ = 72;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<CirculateEvent*>(event);
+ if ((evtype == CirculateEvent::Notify || evtype == CirculateEvent::Request)) {
+ event->type_id_ = 74;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<CirculateEvent*>(e);
+ }
};
auto* event_ = new CirculateEvent;
ReadEvent(event_, buffer);
event_->opcode = static_cast<decltype(event_->opcode)>(evtype);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == PropertyNotifyEvent::opcode) {
- event->type_id_ = 73;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<PropertyNotifyEvent*>(event);
+ event->type_id_ = 75;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<PropertyNotifyEvent*>(e);
+ }
};
auto* event_ = new PropertyNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == SelectionClearEvent::opcode) {
- event->type_id_ = 74;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<SelectionClearEvent*>(event);
+ event->type_id_ = 76;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<SelectionClearEvent*>(e);
+ }
};
auto* event_ = new SelectionClearEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == SelectionRequestEvent::opcode) {
- event->type_id_ = 75;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<SelectionRequestEvent*>(event);
+ event->type_id_ = 77;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<SelectionRequestEvent*>(e);
+ }
};
auto* event_ = new SelectionRequestEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == SelectionNotifyEvent::opcode) {
- event->type_id_ = 76;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<SelectionNotifyEvent*>(event);
+ event->type_id_ = 78;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<SelectionNotifyEvent*>(e);
+ }
};
auto* event_ = new SelectionNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == ColormapNotifyEvent::opcode) {
- event->type_id_ = 77;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<ColormapNotifyEvent*>(event);
+ event->type_id_ = 79;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<ColormapNotifyEvent*>(e);
+ }
};
auto* event_ = new ColormapNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == ClientMessageEvent::opcode) {
- event->type_id_ = 78;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<ClientMessageEvent*>(event);
+ event->type_id_ = 80;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<ClientMessageEvent*>(e);
+ }
};
auto* event_ = new ClientMessageEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (evtype == MappingNotifyEvent::opcode) {
- event->type_id_ = 79;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<MappingNotifyEvent*>(event);
+ event->type_id_ = 81;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<MappingNotifyEvent*>(e);
+ }
};
auto* event_ = new MappingNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xv().present() &&
evtype - conn->xv().first_event() == Xv::VideoNotifyEvent::opcode) {
- event->type_id_ = 81;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Xv::VideoNotifyEvent*>(event);
+ event->type_id_ = 83;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Xv::VideoNotifyEvent*>(e);
+ }
};
auto* event_ = new Xv::VideoNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
if (conn->xv().present() &&
evtype - conn->xv().first_event() == Xv::PortNotifyEvent::opcode) {
- event->type_id_ = 82;
- event->deleter_ = [](void* event) {
- delete reinterpret_cast<Xv::PortNotifyEvent*>(event);
+ event->type_id_ = 84;
+ auto deleter_ = [](void* e) {
+ if (e) {
+ delete reinterpret_cast<Xv::PortNotifyEvent*>(e);
+ }
};
auto* event_ = new Xv::PortNotifyEvent;
ReadEvent(event_, buffer);
- event_->send_event = send_event;
- event->event_ = event_;
+ event->event_ = {event_, deleter_};
event->window_ = event_->GetWindow();
return;
}
- NOTREACHED();
+ // Leave `event` default-initialized.
}
} // namespace x11
diff --git a/ui/gfx/x/generated_protos/record.cc b/ui/gfx/x/generated_protos/record.cc
index 3976979..15e4c00 100644
--- a/ui/gfx/x/generated_protos/record.cc
+++ b/ui/gfx/x/generated_protos/record.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "record.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
@@ -56,7 +57,9 @@
std::stringstream ss_;
ss_ << "Record::BadContextError{";
ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
- ss_ << ".invalid_record = " << static_cast<uint64_t>(invalid_record);
+ ss_ << ".invalid_record = " << static_cast<uint64_t>(invalid_record) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -68,6 +71,8 @@
auto& sequence = (*error_).sequence;
auto& invalid_record = (*error_).invalid_record;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -83,6 +88,12 @@
// invalid_record
Read(&invalid_record, &buf);
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
Future<Record::QueryVersionReply> Record::QueryVersion(
diff --git a/ui/gfx/x/generated_protos/record.h b/ui/gfx/x/generated_protos/record.h
index 123f200..e931cbd 100644
--- a/ui/gfx/x/generated_protos/record.h
+++ b/ui/gfx/x/generated_protos/record.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -97,21 +97,44 @@
};
struct Range8 {
+ bool operator==(const Range8& other) const {
+ return first == other.first && last == other.last;
+ }
+
uint8_t first{};
uint8_t last{};
};
struct Range16 {
+ bool operator==(const Range16& other) const {
+ return first == other.first && last == other.last;
+ }
+
uint16_t first{};
uint16_t last{};
};
struct ExtRange {
+ bool operator==(const ExtRange& other) const {
+ return major == other.major && minor == other.minor;
+ }
+
Range8 major{};
Range16 minor{};
};
struct Range {
+ bool operator==(const Range& other) const {
+ return core_requests == other.core_requests &&
+ core_replies == other.core_replies &&
+ ext_requests == other.ext_requests &&
+ ext_replies == other.ext_replies &&
+ delivered_events == other.delivered_events &&
+ device_events == other.device_events && errors == other.errors &&
+ client_started == other.client_started &&
+ client_died == other.client_died;
+ }
+
Range8 core_requests{};
Range8 core_replies{};
ExtRange ext_requests{};
@@ -124,6 +147,10 @@
};
struct ClientInfo {
+ bool operator==(const ClientInfo& other) const {
+ return client_resource == other.client_resource && ranges == other.ranges;
+ }
+
ClientSpec client_resource{};
std::vector<Range> ranges{};
};
@@ -131,6 +158,8 @@
struct BadContextError : public x11::Error {
uint16_t sequence{};
uint32_t invalid_record{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
diff --git a/ui/gfx/x/generated_protos/render.cc b/ui/gfx/x/generated_protos/render.cc
index 553afbd..4d20d3c 100644
--- a/ui/gfx/x/generated_protos/render.cc
+++ b/ui/gfx/x/generated_protos/render.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "render.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
@@ -55,7 +56,10 @@
std::string Render::PictFormatError::ToString() const {
std::stringstream ss_;
ss_ << "Render::PictFormatError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -66,6 +70,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -78,12 +85,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string Render::PictureError::ToString() const {
std::stringstream ss_;
ss_ << "Render::PictureError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -94,6 +113,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -106,12 +128,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string Render::PictOpError::ToString() const {
std::stringstream ss_;
ss_ << "Render::PictOpError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -122,6 +156,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -134,12 +171,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string Render::GlyphSetError::ToString() const {
std::stringstream ss_;
ss_ << "Render::GlyphSetError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -150,6 +199,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -162,12 +214,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string Render::GlyphError::ToString() const {
std::stringstream ss_;
ss_ << "Render::GlyphError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -178,6 +242,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -190,6 +257,15 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
Future<Render::QueryVersionReply> Render::QueryVersion(
@@ -2697,7 +2773,7 @@
}
// num_stops
- num_stops = stops.size();
+ num_stops = colors.size();
buf.Write(&num_stops);
// stops
@@ -2810,7 +2886,7 @@
buf.Write(&outer_radius);
// num_stops
- num_stops = stops.size();
+ num_stops = colors.size();
buf.Write(&num_stops);
// stops
@@ -2908,7 +2984,7 @@
buf.Write(&angle);
// num_stops
- num_stops = stops.size();
+ num_stops = colors.size();
buf.Write(&num_stops);
// stops
diff --git a/ui/gfx/x/generated_protos/render.h b/ui/gfx/x/generated_protos/render.h
index 62d784f..4f6af46 100644
--- a/ui/gfx/x/generated_protos/render.h
+++ b/ui/gfx/x/generated_protos/render.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -197,35 +197,58 @@
struct PictFormatError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct PictureError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct PictOpError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct GlyphSetError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct GlyphError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct DirectFormat {
+ bool operator==(const DirectFormat& other) const {
+ return red_shift == other.red_shift && red_mask == other.red_mask &&
+ green_shift == other.green_shift &&
+ green_mask == other.green_mask && blue_shift == other.blue_shift &&
+ blue_mask == other.blue_mask && alpha_shift == other.alpha_shift &&
+ alpha_mask == other.alpha_mask;
+ }
+
uint16_t red_shift{};
uint16_t red_mask{};
uint16_t green_shift{};
@@ -237,6 +260,11 @@
};
struct PictFormInfo {
+ bool operator==(const PictFormInfo& other) const {
+ return id == other.id && type == other.type && depth == other.depth &&
+ direct == other.direct && colormap == other.colormap;
+ }
+
PictFormat id{};
PictType type{};
uint8_t depth{};
@@ -245,21 +273,38 @@
};
struct PictVisual {
+ bool operator==(const PictVisual& other) const {
+ return visual == other.visual && format == other.format;
+ }
+
VisualId visual{};
PictFormat format{};
};
struct PictDepth {
+ bool operator==(const PictDepth& other) const {
+ return depth == other.depth && visuals == other.visuals;
+ }
+
uint8_t depth{};
std::vector<PictVisual> visuals{};
};
struct PictScreen {
+ bool operator==(const PictScreen& other) const {
+ return fallback == other.fallback && depths == other.depths;
+ }
+
PictFormat fallback{};
std::vector<PictDepth> depths{};
};
struct IndexValue {
+ bool operator==(const IndexValue& other) const {
+ return pixel == other.pixel && red == other.red && green == other.green &&
+ blue == other.blue && alpha == other.alpha;
+ }
+
uint32_t pixel{};
uint16_t red{};
uint16_t green{};
@@ -268,6 +313,11 @@
};
struct Color {
+ bool operator==(const Color& other) const {
+ return red == other.red && green == other.green && blue == other.blue &&
+ alpha == other.alpha;
+ }
+
uint16_t red{};
uint16_t green{};
uint16_t blue{};
@@ -275,22 +325,39 @@
};
struct PointFix {
+ bool operator==(const PointFix& other) const {
+ return x == other.x && y == other.y;
+ }
+
Fixed x{};
Fixed y{};
};
struct LineFix {
+ bool operator==(const LineFix& other) const {
+ return p1 == other.p1 && p2 == other.p2;
+ }
+
PointFix p1{};
PointFix p2{};
};
struct Triangle {
+ bool operator==(const Triangle& other) const {
+ return p1 == other.p1 && p2 == other.p2 && p3 == other.p3;
+ }
+
PointFix p1{};
PointFix p2{};
PointFix p3{};
};
struct Trapezoid {
+ bool operator==(const Trapezoid& other) const {
+ return top == other.top && bottom == other.bottom && left == other.left &&
+ right == other.right;
+ }
+
Fixed top{};
Fixed bottom{};
LineFix left{};
@@ -298,6 +365,11 @@
};
struct GlyphInfo {
+ bool operator==(const GlyphInfo& other) const {
+ return width == other.width && height == other.height && x == other.x &&
+ y == other.y && x_off == other.x_off && y_off == other.y_off;
+ }
+
uint16_t width{};
uint16_t height{};
int16_t x{};
@@ -307,6 +379,14 @@
};
struct Transform {
+ bool operator==(const Transform& other) const {
+ return matrix11 == other.matrix11 && matrix12 == other.matrix12 &&
+ matrix13 == other.matrix13 && matrix21 == other.matrix21 &&
+ matrix22 == other.matrix22 && matrix23 == other.matrix23 &&
+ matrix31 == other.matrix31 && matrix32 == other.matrix32 &&
+ matrix33 == other.matrix33;
+ }
+
Fixed matrix11{};
Fixed matrix12{};
Fixed matrix13{};
@@ -319,17 +399,29 @@
};
struct AnimationCursorElement {
+ bool operator==(const AnimationCursorElement& other) const {
+ return cursor == other.cursor && delay == other.delay;
+ }
+
Cursor cursor{};
uint32_t delay{};
};
struct SpanFix {
+ bool operator==(const SpanFix& other) const {
+ return l == other.l && r == other.r && y == other.y;
+ }
+
Fixed l{};
Fixed r{};
Fixed y{};
};
struct Trap {
+ bool operator==(const Trap& other) const {
+ return top == other.top && bot == other.bot;
+ }
+
SpanFix top{};
SpanFix bot{};
};
diff --git a/ui/gfx/x/generated_protos/res.cc b/ui/gfx/x/generated_protos/res.cc
index a17dcff..c4d5a79 100644
--- a/ui/gfx/x/generated_protos/res.cc
+++ b/ui/gfx/x/generated_protos/res.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "res.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/res.h b/ui/gfx/x/generated_protos/res.h
index 11bd310..36be110 100644
--- a/ui/gfx/x/generated_protos/res.h
+++ b/ui/gfx/x/generated_protos/res.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -86,32 +86,59 @@
};
struct Client {
+ bool operator==(const Client& other) const {
+ return resource_base == other.resource_base &&
+ resource_mask == other.resource_mask;
+ }
+
uint32_t resource_base{};
uint32_t resource_mask{};
};
struct Type {
+ bool operator==(const Type& other) const {
+ return resource_type == other.resource_type && count == other.count;
+ }
+
Atom resource_type{};
uint32_t count{};
};
struct ClientIdSpec {
+ bool operator==(const ClientIdSpec& other) const {
+ return client == other.client && mask == other.mask;
+ }
+
uint32_t client{};
ClientIdMask mask{};
};
struct ClientIdValue {
+ bool operator==(const ClientIdValue& other) const {
+ return spec == other.spec && length == other.length &&
+ value == other.value;
+ }
+
ClientIdSpec spec{};
uint32_t length{};
std::vector<uint32_t> value{};
};
struct ResourceIdSpec {
+ bool operator==(const ResourceIdSpec& other) const {
+ return resource == other.resource && type == other.type;
+ }
+
uint32_t resource{};
uint32_t type{};
};
struct ResourceSizeSpec {
+ bool operator==(const ResourceSizeSpec& other) const {
+ return spec == other.spec && bytes == other.bytes &&
+ ref_count == other.ref_count && use_count == other.use_count;
+ }
+
ResourceIdSpec spec{};
uint32_t bytes{};
uint32_t ref_count{};
@@ -119,6 +146,10 @@
};
struct ResourceSizeValue {
+ bool operator==(const ResourceSizeValue& other) const {
+ return size == other.size && cross_references == other.cross_references;
+ }
+
ResourceSizeSpec size{};
std::vector<ResourceSizeSpec> cross_references{};
};
diff --git a/ui/gfx/x/generated_protos/screensaver.cc b/ui/gfx/x/generated_protos/screensaver.cc
index b28f663..af18262 100644
--- a/ui/gfx/x/generated_protos/screensaver.cc
+++ b/ui/gfx/x/generated_protos/screensaver.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "screensaver.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/screensaver.h b/ui/gfx/x/generated_protos/screensaver.h
index 7f43bcd..02fc2b1 100644
--- a/ui/gfx/x/generated_protos/screensaver.h
+++ b/ui/gfx/x/generated_protos/screensaver.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -101,7 +101,6 @@
struct NotifyEvent {
static constexpr int type_id = 13;
static constexpr uint8_t opcode = 0;
- bool send_event{};
State state{};
uint16_t sequence{};
Time time{};
diff --git a/ui/gfx/x/generated_protos/shape.cc b/ui/gfx/x/generated_protos/shape.cc
index 946080a..7f7e13e 100644
--- a/ui/gfx/x/generated_protos/shape.cc
+++ b/ui/gfx/x/generated_protos/shape.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "shape.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/shape.h b/ui/gfx/x/generated_protos/shape.h
index 7262c39..3fd96d0 100644
--- a/ui/gfx/x/generated_protos/shape.h
+++ b/ui/gfx/x/generated_protos/shape.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -101,7 +101,6 @@
struct NotifyEvent {
static constexpr int type_id = 14;
static constexpr uint8_t opcode = 0;
- bool send_event{};
Sk shape_kind{};
uint16_t sequence{};
Window affected_window{};
diff --git a/ui/gfx/x/generated_protos/shm.cc b/ui/gfx/x/generated_protos/shm.cc
index fc795c6..c99568b 100644
--- a/ui/gfx/x/generated_protos/shm.cc
+++ b/ui/gfx/x/generated_protos/shm.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "shm.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/shm.h b/ui/gfx/x/generated_protos/shm.h
index 6df3185..81e83ec 100644
--- a/ui/gfx/x/generated_protos/shm.h
+++ b/ui/gfx/x/generated_protos/shm.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -85,7 +85,6 @@
struct CompletionEvent {
static constexpr int type_id = 15;
static constexpr uint8_t opcode = 0;
- bool send_event{};
uint16_t sequence{};
Drawable drawable{};
uint16_t minor_event{};
diff --git a/ui/gfx/x/generated_protos/sync.cc b/ui/gfx/x/generated_protos/sync.cc
index f175c29..5aaef91 100644
--- a/ui/gfx/x/generated_protos/sync.cc
+++ b/ui/gfx/x/generated_protos/sync.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "sync.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/sync.h b/ui/gfx/x/generated_protos/sync.h
index 85ef3d1..7f98678 100644
--- a/ui/gfx/x/generated_protos/sync.h
+++ b/ui/gfx/x/generated_protos/sync.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -114,17 +114,31 @@
};
struct Int64 {
+ bool operator==(const Int64& other) const {
+ return hi == other.hi && lo == other.lo;
+ }
+
int32_t hi{};
uint32_t lo{};
};
struct SystemCounter {
+ bool operator==(const SystemCounter& other) const {
+ return counter == other.counter && resolution == other.resolution &&
+ name == other.name;
+ }
+
Counter counter{};
Int64 resolution{};
std::string name{};
};
struct Trigger {
+ bool operator==(const Trigger& other) const {
+ return counter == other.counter && wait_type == other.wait_type &&
+ wait_value == other.wait_value && test_type == other.test_type;
+ }
+
Counter counter{};
Valuetype wait_type{};
Int64 wait_value{};
@@ -132,6 +146,11 @@
};
struct WaitCondition {
+ bool operator==(const WaitCondition& other) const {
+ return trigger == other.trigger &&
+ event_threshold == other.event_threshold;
+ }
+
Trigger trigger{};
Int64 event_threshold{};
};
@@ -157,7 +176,6 @@
struct CounterNotifyEvent {
static constexpr int type_id = 16;
static constexpr uint8_t opcode = 0;
- bool send_event{};
uint8_t kind{};
uint16_t sequence{};
Counter counter{};
@@ -173,7 +191,6 @@
struct AlarmNotifyEvent {
static constexpr int type_id = 17;
static constexpr uint8_t opcode = 1;
- bool send_event{};
uint8_t kind{};
uint16_t sequence{};
Alarm alarm{};
diff --git a/ui/gfx/x/generated_protos/xc_misc.cc b/ui/gfx/x/generated_protos/xc_misc.cc
index e75c0a8..37a21d9 100644
--- a/ui/gfx/x/generated_protos/xc_misc.cc
+++ b/ui/gfx/x/generated_protos/xc_misc.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "xc_misc.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/xc_misc.h b/ui/gfx/x/generated_protos/xc_misc.h
index ea890fe..b6e18e9 100644
--- a/ui/gfx/x/generated_protos/xc_misc.h
+++ b/ui/gfx/x/generated_protos/xc_misc.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/generated_protos/xevie.cc b/ui/gfx/x/generated_protos/xevie.cc
index 8eeb44d..3c436b3 100644
--- a/ui/gfx/x/generated_protos/xevie.cc
+++ b/ui/gfx/x/generated_protos/xevie.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "xevie.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/xevie.h b/ui/gfx/x/generated_protos/xevie.h
index be6723c..8442436 100644
--- a/ui/gfx/x/generated_protos/xevie.h
+++ b/ui/gfx/x/generated_protos/xevie.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -85,7 +85,9 @@
Modified = 1,
};
- struct Event {};
+ struct Event {
+ bool operator==(const Event& other) const { return true; }
+ };
struct QueryVersionRequest {
uint16_t client_major_version{};
diff --git a/ui/gfx/x/generated_protos/xf86dri.cc b/ui/gfx/x/generated_protos/xf86dri.cc
index 4acebbe..f834758 100644
--- a/ui/gfx/x/generated_protos/xf86dri.cc
+++ b/ui/gfx/x/generated_protos/xf86dri.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "xf86dri.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/xf86dri.h b/ui/gfx/x/generated_protos/xf86dri.h
index 42cbd47..16726d3 100644
--- a/ui/gfx/x/generated_protos/xf86dri.h
+++ b/ui/gfx/x/generated_protos/xf86dri.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -81,6 +81,11 @@
Connection* connection() const { return connection_; }
struct DrmClipRect {
+ bool operator==(const DrmClipRect& other) const {
+ return x1 == other.x1 && y1 == other.y1 && x2 == other.x2 &&
+ x3 == other.x3;
+ }
+
int16_t x1{};
int16_t y1{};
int16_t x2{};
diff --git a/ui/gfx/x/generated_protos/xf86vidmode.cc b/ui/gfx/x/generated_protos/xf86vidmode.cc
index c08c336..c56d271 100644
--- a/ui/gfx/x/generated_protos/xf86vidmode.cc
+++ b/ui/gfx/x/generated_protos/xf86vidmode.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "xf86vidmode.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
@@ -56,7 +57,10 @@
std::string XF86VidMode::BadClockError::ToString() const {
std::stringstream ss_;
ss_ << "XF86VidMode::BadClockError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -67,6 +71,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -79,12 +86,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string XF86VidMode::BadHTimingsError::ToString() const {
std::stringstream ss_;
ss_ << "XF86VidMode::BadHTimingsError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -96,6 +115,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -108,12 +130,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string XF86VidMode::BadVTimingsError::ToString() const {
std::stringstream ss_;
ss_ << "XF86VidMode::BadVTimingsError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -125,6 +159,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -137,12 +174,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string XF86VidMode::ModeUnsuitableError::ToString() const {
std::stringstream ss_;
ss_ << "XF86VidMode::ModeUnsuitableError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -154,6 +203,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -166,12 +218,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string XF86VidMode::ExtensionDisabledError::ToString() const {
std::stringstream ss_;
ss_ << "XF86VidMode::ExtensionDisabledError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -183,6 +247,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -195,12 +262,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string XF86VidMode::ClientNotLocalError::ToString() const {
std::stringstream ss_;
ss_ << "XF86VidMode::ClientNotLocalError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -212,6 +291,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -224,12 +306,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string XF86VidMode::ZoomLockedError::ToString() const {
std::stringstream ss_;
ss_ << "XF86VidMode::ZoomLockedError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -241,6 +335,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -253,6 +350,15 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
Future<XF86VidMode::QueryVersionReply> XF86VidMode::QueryVersion(
diff --git a/ui/gfx/x/generated_protos/xf86vidmode.h b/ui/gfx/x/generated_protos/xf86vidmode.h
index fa451a2..6b871f1 100644
--- a/ui/gfx/x/generated_protos/xf86vidmode.h
+++ b/ui/gfx/x/generated_protos/xf86vidmode.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -110,6 +110,15 @@
};
struct ModeInfo {
+ bool operator==(const ModeInfo& other) const {
+ return dotclock == other.dotclock && hdisplay == other.hdisplay &&
+ hsyncstart == other.hsyncstart && hsyncend == other.hsyncend &&
+ htotal == other.htotal && hskew == other.hskew &&
+ vdisplay == other.vdisplay && vsyncstart == other.vsyncstart &&
+ vsyncend == other.vsyncend && vtotal == other.vtotal &&
+ flags == other.flags && privsize == other.privsize;
+ }
+
DotClock dotclock{};
uint16_t hdisplay{};
uint16_t hsyncstart{};
@@ -126,42 +135,63 @@
struct BadClockError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct BadHTimingsError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct BadVTimingsError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct ModeUnsuitableError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct ExtensionDisabledError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct ClientNotLocalError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct ZoomLockedError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
diff --git a/ui/gfx/x/generated_protos/xfixes.cc b/ui/gfx/x/generated_protos/xfixes.cc
index 88cc351..b53c431 100644
--- a/ui/gfx/x/generated_protos/xfixes.cc
+++ b/ui/gfx/x/generated_protos/xfixes.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "xfixes.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
@@ -146,7 +147,10 @@
std::string XFixes::BadRegionError::ToString() const {
std::stringstream ss_;
ss_ << "XFixes::BadRegionError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -157,6 +161,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -169,6 +176,15 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
Future<XFixes::QueryVersionReply> XFixes::QueryVersion(
@@ -1984,4 +2000,110 @@
XFixes::DeletePointerBarrierRequest{barrier});
}
+Future<void> XFixes::SetClientDisconnectMode(
+ const XFixes::SetClientDisconnectModeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ auto& disconnect_mode = request.disconnect_mode;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 33;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ // disconnect_mode
+ uint32_t tmp10;
+ tmp10 = static_cast<uint32_t>(disconnect_mode);
+ buf.Write(&tmp10);
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<void>(&buf, "XFixes::SetClientDisconnectMode",
+ false);
+}
+
+Future<void> XFixes::SetClientDisconnectMode(
+ const ClientDisconnectFlags& disconnect_mode) {
+ return XFixes::SetClientDisconnectMode(
+ XFixes::SetClientDisconnectModeRequest{disconnect_mode});
+}
+
+Future<XFixes::GetClientDisconnectModeReply> XFixes::GetClientDisconnectMode(
+ const XFixes::GetClientDisconnectModeRequest& request) {
+ if (!connection_->Ready() || !present())
+ return {};
+
+ WriteBuffer buf;
+
+ // major_opcode
+ uint8_t major_opcode = info_.major_opcode;
+ buf.Write(&major_opcode);
+
+ // minor_opcode
+ uint8_t minor_opcode = 34;
+ buf.Write(&minor_opcode);
+
+ // length
+ // Caller fills in length for writes.
+ Pad(&buf, sizeof(uint16_t));
+
+ Align(&buf, 4);
+
+ return connection_->SendRequest<XFixes::GetClientDisconnectModeReply>(
+ &buf, "XFixes::GetClientDisconnectMode", false);
+}
+
+Future<XFixes::GetClientDisconnectModeReply> XFixes::GetClientDisconnectMode() {
+ return XFixes::GetClientDisconnectMode(
+ XFixes::GetClientDisconnectModeRequest{});
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+std::unique_ptr<XFixes::GetClientDisconnectModeReply> detail::ReadReply<
+ XFixes::GetClientDisconnectModeReply>(ReadBuffer* buffer) {
+ auto& buf = *buffer;
+ auto reply = std::make_unique<XFixes::GetClientDisconnectModeReply>();
+
+ auto& sequence = (*reply).sequence;
+ auto& disconnect_mode = (*reply).disconnect_mode;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // pad0
+ Pad(&buf, 1);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // disconnect_mode
+ uint32_t tmp11;
+ Read(&tmp11, &buf);
+ disconnect_mode = static_cast<XFixes::ClientDisconnectFlags>(tmp11);
+
+ // pad1
+ Pad(&buf, 20);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset < 32 ? 0 : buf.offset - 32, 4 * length);
+
+ return reply;
+}
+
} // namespace x11
diff --git a/ui/gfx/x/generated_protos/xfixes.h b/ui/gfx/x/generated_protos/xfixes.h
index b880acd..719e67e 100644
--- a/ui/gfx/x/generated_protos/xfixes.h
+++ b/ui/gfx/x/generated_protos/xfixes.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -70,7 +70,7 @@
class COMPONENT_EXPORT(X11) XFixes {
public:
- static constexpr unsigned major_version = 5;
+ static constexpr unsigned major_version = 6;
static constexpr unsigned minor_version = 0;
XFixes(Connection* connection, const x11::QueryExtensionReply& info);
@@ -130,10 +130,14 @@
NegativeY = 1 << 3,
};
+ enum class ClientDisconnectFlags : int {
+ Default = 0,
+ Terminate = 1 << 0,
+ };
+
struct SelectionNotifyEvent {
static constexpr int type_id = 18;
static constexpr uint8_t opcode = 0;
- bool send_event{};
SelectionEvent subtype{};
uint16_t sequence{};
Window window{};
@@ -148,7 +152,6 @@
struct CursorNotifyEvent {
static constexpr int type_id = 19;
static constexpr uint8_t opcode = 1;
- bool send_event{};
CursorNotify subtype{};
uint16_t sequence{};
Window window{};
@@ -161,6 +164,9 @@
struct BadRegionError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
@@ -643,6 +649,33 @@
Future<void> DeletePointerBarrier(const Barrier& barrier = {});
+ struct SetClientDisconnectModeRequest {
+ ClientDisconnectFlags disconnect_mode{};
+ };
+
+ using SetClientDisconnectModeResponse = Response<void>;
+
+ Future<void> SetClientDisconnectMode(
+ const SetClientDisconnectModeRequest& request);
+
+ Future<void> SetClientDisconnectMode(
+ const ClientDisconnectFlags& disconnect_mode = {});
+
+ struct GetClientDisconnectModeRequest {};
+
+ struct GetClientDisconnectModeReply {
+ uint16_t sequence{};
+ ClientDisconnectFlags disconnect_mode{};
+ };
+
+ using GetClientDisconnectModeResponse =
+ Response<GetClientDisconnectModeReply>;
+
+ Future<GetClientDisconnectModeReply> GetClientDisconnectMode(
+ const GetClientDisconnectModeRequest& request);
+
+ Future<GetClientDisconnectModeReply> GetClientDisconnectMode();
+
private:
Connection* const connection_;
x11::QueryExtensionReply info_{};
@@ -792,4 +825,20 @@
static_cast<T>(r));
}
+inline constexpr x11::XFixes::ClientDisconnectFlags operator|(
+ x11::XFixes::ClientDisconnectFlags l,
+ x11::XFixes::ClientDisconnectFlags r) {
+ using T = std::underlying_type_t<x11::XFixes::ClientDisconnectFlags>;
+ return static_cast<x11::XFixes::ClientDisconnectFlags>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::XFixes::ClientDisconnectFlags operator&(
+ x11::XFixes::ClientDisconnectFlags l,
+ x11::XFixes::ClientDisconnectFlags r) {
+ using T = std::underlying_type_t<x11::XFixes::ClientDisconnectFlags>;
+ return static_cast<x11::XFixes::ClientDisconnectFlags>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
#endif // UI_GFX_X_GENERATED_PROTOS_XFIXES_H_
diff --git a/ui/gfx/x/generated_protos/xinerama.cc b/ui/gfx/x/generated_protos/xinerama.cc
index e184714..d59d4a0 100644
--- a/ui/gfx/x/generated_protos/xinerama.cc
+++ b/ui/gfx/x/generated_protos/xinerama.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "xinerama.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/xinerama.h b/ui/gfx/x/generated_protos/xinerama.h
index 367d70c..da96956 100644
--- a/ui/gfx/x/generated_protos/xinerama.h
+++ b/ui/gfx/x/generated_protos/xinerama.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -81,6 +81,11 @@
Connection* connection() const { return connection_; }
struct ScreenInfo {
+ bool operator==(const ScreenInfo& other) const {
+ return x_org == other.x_org && y_org == other.y_org &&
+ width == other.width && height == other.height;
+ }
+
int16_t x_org{};
int16_t y_org{};
uint16_t width{};
diff --git a/ui/gfx/x/generated_protos/xinput.cc b/ui/gfx/x/generated_protos/xinput.cc
index f98f5b2..f5f3d8c 100644
--- a/ui/gfx/x/generated_protos/xinput.cc
+++ b/ui/gfx/x/generated_protos/xinput.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "xinput.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
@@ -733,6 +734,16 @@
// num_touches
Read(&num_touches, &buf);
}
+ if (CaseEq(data_expr, Input::DeviceClassType::Gesture)) {
+ data.gesture.emplace();
+ auto& num_touches = (*data.gesture).num_touches;
+
+ // num_touches
+ Read(&num_touches, &buf);
+
+ // pad2
+ Pad(&buf, 1);
+ }
}
}
@@ -1484,10 +1495,305 @@
DCHECK_EQ(buf.offset, 32 + 4 * length);
}
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::GesturePinchEvent>(Input::GesturePinchEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& deviceid = (*event_).deviceid;
+ auto& time = (*event_).time;
+ auto& detail = (*event_).detail;
+ auto& root = (*event_).root;
+ auto& event = (*event_).event;
+ auto& child = (*event_).child;
+ auto& root_x = (*event_).root_x;
+ auto& root_y = (*event_).root_y;
+ auto& event_x = (*event_).event_x;
+ auto& event_y = (*event_).event_y;
+ auto& delta_x = (*event_).delta_x;
+ auto& delta_y = (*event_).delta_y;
+ auto& delta_unaccel_x = (*event_).delta_unaccel_x;
+ auto& delta_unaccel_y = (*event_).delta_unaccel_y;
+ auto& scale = (*event_).scale;
+ auto& delta_angle = (*event_).delta_angle;
+ auto& sourceid = (*event_).sourceid;
+ auto& mods = (*event_).mods;
+ auto& group = (*event_).group;
+ auto& flags = (*event_).flags;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ uint8_t extension;
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_type
+ uint16_t event_type;
+ Read(&event_type, &buf);
+
+ // deviceid
+ Read(&deviceid, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // detail
+ Read(&detail, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // child
+ Read(&child, &buf);
+
+ // root_x
+ Read(&root_x, &buf);
+
+ // root_y
+ Read(&root_y, &buf);
+
+ // event_x
+ Read(&event_x, &buf);
+
+ // event_y
+ Read(&event_y, &buf);
+
+ // delta_x
+ Read(&delta_x, &buf);
+
+ // delta_y
+ Read(&delta_y, &buf);
+
+ // delta_unaccel_x
+ Read(&delta_unaccel_x, &buf);
+
+ // delta_unaccel_y
+ Read(&delta_unaccel_y, &buf);
+
+ // scale
+ Read(&scale, &buf);
+
+ // delta_angle
+ Read(&delta_angle, &buf);
+
+ // sourceid
+ Read(&sourceid, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // mods
+ {
+ auto& base = mods.base;
+ auto& latched = mods.latched;
+ auto& locked = mods.locked;
+ auto& effective = mods.effective;
+
+ // base
+ Read(&base, &buf);
+
+ // latched
+ Read(&latched, &buf);
+
+ // locked
+ Read(&locked, &buf);
+
+ // effective
+ Read(&effective, &buf);
+ }
+
+ // group
+ {
+ auto& base = group.base;
+ auto& latched = group.latched;
+ auto& locked = group.locked;
+ auto& effective = group.effective;
+
+ // base
+ Read(&base, &buf);
+
+ // latched
+ Read(&latched, &buf);
+
+ // locked
+ Read(&locked, &buf);
+
+ // effective
+ Read(&effective, &buf);
+ }
+
+ // flags
+ uint32_t tmp27;
+ Read(&tmp27, &buf);
+ flags = static_cast<Input::GesturePinchEventFlags>(tmp27);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset, 32 + 4 * length);
+}
+
+template <>
+COMPONENT_EXPORT(X11)
+void ReadEvent<Input::GestureSwipeEvent>(Input::GestureSwipeEvent* event_,
+ ReadBuffer* buffer) {
+ auto& buf = *buffer;
+
+ auto& sequence = (*event_).sequence;
+ auto& deviceid = (*event_).deviceid;
+ auto& time = (*event_).time;
+ auto& detail = (*event_).detail;
+ auto& root = (*event_).root;
+ auto& event = (*event_).event;
+ auto& child = (*event_).child;
+ auto& root_x = (*event_).root_x;
+ auto& root_y = (*event_).root_y;
+ auto& event_x = (*event_).event_x;
+ auto& event_y = (*event_).event_y;
+ auto& delta_x = (*event_).delta_x;
+ auto& delta_y = (*event_).delta_y;
+ auto& delta_unaccel_x = (*event_).delta_unaccel_x;
+ auto& delta_unaccel_y = (*event_).delta_unaccel_y;
+ auto& sourceid = (*event_).sourceid;
+ auto& mods = (*event_).mods;
+ auto& group = (*event_).group;
+ auto& flags = (*event_).flags;
+
+ // response_type
+ uint8_t response_type;
+ Read(&response_type, &buf);
+
+ // extension
+ uint8_t extension;
+ Read(&extension, &buf);
+
+ // sequence
+ Read(&sequence, &buf);
+
+ // length
+ uint32_t length;
+ Read(&length, &buf);
+
+ // event_type
+ uint16_t event_type;
+ Read(&event_type, &buf);
+
+ // deviceid
+ Read(&deviceid, &buf);
+
+ // time
+ Read(&time, &buf);
+
+ // detail
+ Read(&detail, &buf);
+
+ // root
+ Read(&root, &buf);
+
+ // event
+ Read(&event, &buf);
+
+ // child
+ Read(&child, &buf);
+
+ // root_x
+ Read(&root_x, &buf);
+
+ // root_y
+ Read(&root_y, &buf);
+
+ // event_x
+ Read(&event_x, &buf);
+
+ // event_y
+ Read(&event_y, &buf);
+
+ // delta_x
+ Read(&delta_x, &buf);
+
+ // delta_y
+ Read(&delta_y, &buf);
+
+ // delta_unaccel_x
+ Read(&delta_unaccel_x, &buf);
+
+ // delta_unaccel_y
+ Read(&delta_unaccel_y, &buf);
+
+ // sourceid
+ Read(&sourceid, &buf);
+
+ // pad0
+ Pad(&buf, 2);
+
+ // mods
+ {
+ auto& base = mods.base;
+ auto& latched = mods.latched;
+ auto& locked = mods.locked;
+ auto& effective = mods.effective;
+
+ // base
+ Read(&base, &buf);
+
+ // latched
+ Read(&latched, &buf);
+
+ // locked
+ Read(&locked, &buf);
+
+ // effective
+ Read(&effective, &buf);
+ }
+
+ // group
+ {
+ auto& base = group.base;
+ auto& latched = group.latched;
+ auto& locked = group.locked;
+ auto& effective = group.effective;
+
+ // base
+ Read(&base, &buf);
+
+ // latched
+ Read(&latched, &buf);
+
+ // locked
+ Read(&locked, &buf);
+
+ // effective
+ Read(&effective, &buf);
+ }
+
+ // flags
+ uint32_t tmp28;
+ Read(&tmp28, &buf);
+ flags = static_cast<Input::GestureSwipeEventFlags>(tmp28);
+
+ Align(&buf, 4);
+ DCHECK_EQ(buf.offset, 32 + 4 * length);
+}
+
std::string Input::DeviceError::ToString() const {
std::stringstream ss_;
ss_ << "Input::DeviceError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -1498,6 +1804,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -1510,12 +1819,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string Input::EventError::ToString() const {
std::stringstream ss_;
ss_ << "Input::EventError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -1526,6 +1847,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -1538,12 +1862,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string Input::ModeError::ToString() const {
std::stringstream ss_;
ss_ << "Input::ModeError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -1553,6 +1889,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -1565,12 +1904,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string Input::DeviceBusyError::ToString() const {
std::stringstream ss_;
ss_ << "Input::DeviceBusyError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -1581,6 +1932,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -1593,12 +1947,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string Input::ClassError::ToString() const {
std::stringstream ss_;
ss_ << "Input::ClassError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -1609,6 +1975,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -1621,6 +1990,15 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
Future<Input::GetExtensionVersionReply> Input::GetExtensionVersion(
@@ -1800,9 +2178,9 @@
Read(&num_class_info, &buf);
// device_use
- uint8_t tmp27;
- Read(&tmp27, &buf);
- device_use = static_cast<Input::DeviceUse>(tmp27);
+ uint8_t tmp29;
+ Read(&tmp29, &buf);
+ device_use = static_cast<Input::DeviceUse>(tmp29);
// pad0
Pad(&buf, 1);
@@ -1810,7 +2188,7 @@
}
// infos
- auto sum28_ = SumOf(
+ auto sum30_ = SumOf(
[](auto& listelem_ref) {
auto& device_type = listelem_ref.device_type;
auto& device_id = listelem_ref.device_id;
@@ -1820,7 +2198,7 @@
return num_class_info;
},
devices);
- infos.resize(sum28_);
+ infos.resize(sum30_);
for (auto& infos_elem : infos) {
// infos_elem
{
@@ -1829,9 +2207,9 @@
auto& info = infos_elem;
// class_id
- uint8_t tmp29;
- Read(&tmp29, &buf);
- class_id = static_cast<Input::InputClass>(tmp29);
+ uint8_t tmp31;
+ Read(&tmp31, &buf);
+ class_id = static_cast<Input::InputClass>(tmp31);
// len
Read(&len, &buf);
@@ -1874,9 +2252,9 @@
Read(&axes_len, &buf);
// mode
- uint8_t tmp30;
- Read(&tmp30, &buf);
- mode = static_cast<Input::ValuatorMode>(tmp30);
+ uint8_t tmp32;
+ Read(&tmp32, &buf);
+ mode = static_cast<Input::ValuatorMode>(tmp32);
// motion_size
Read(&motion_size, &buf);
@@ -2012,9 +2390,9 @@
auto& event_type_base = class_info_elem.event_type_base;
// class_id
- uint8_t tmp31;
- Read(&tmp31, &buf);
- class_id = static_cast<Input::InputClass>(tmp31);
+ uint8_t tmp33;
+ Read(&tmp33, &buf);
+ class_id = static_cast<Input::InputClass>(tmp33);
// event_type_base
Read(&event_type_base, &buf);
@@ -2091,9 +2469,9 @@
buf.Write(&device_id);
// mode
- uint8_t tmp32;
- tmp32 = static_cast<uint8_t>(mode);
- buf.Write(&tmp32);
+ uint8_t tmp34;
+ tmp34 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp34);
// pad0
Pad(&buf, 2);
@@ -2136,9 +2514,9 @@
Read(&length, &buf);
// status
- uint8_t tmp33;
- Read(&tmp33, &buf);
- status = static_cast<GrabStatus>(tmp33);
+ uint8_t tmp35;
+ Read(&tmp35, &buf);
+ status = static_cast<GrabStatus>(tmp35);
// pad0
Pad(&buf, 23);
@@ -2332,9 +2710,9 @@
buf.Write(&num_classes);
// mode
- uint8_t tmp34;
- tmp34 = static_cast<uint8_t>(mode);
- buf.Write(&tmp34);
+ uint8_t tmp36;
+ tmp36 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp36);
// pad0
Pad(&buf, 1);
@@ -2528,9 +2906,9 @@
Read(&num_axes, &buf);
// device_mode
- uint8_t tmp35;
- Read(&tmp35, &buf);
- device_mode = static_cast<Input::ValuatorMode>(tmp35);
+ uint8_t tmp37;
+ Read(&tmp37, &buf);
+ device_mode = static_cast<Input::ValuatorMode>(tmp37);
// pad0
Pad(&buf, 18);
@@ -2627,9 +3005,9 @@
Read(&length, &buf);
// status
- uint8_t tmp36;
- Read(&tmp36, &buf);
- status = static_cast<GrabStatus>(tmp36);
+ uint8_t tmp38;
+ Read(&tmp38, &buf);
+ status = static_cast<GrabStatus>(tmp38);
// pad0
Pad(&buf, 23);
@@ -2715,9 +3093,9 @@
Read(&length, &buf);
// status
- uint8_t tmp37;
- Read(&tmp37, &buf);
- status = static_cast<GrabStatus>(tmp37);
+ uint8_t tmp39;
+ Read(&tmp39, &buf);
+ status = static_cast<GrabStatus>(tmp39);
// pad0
Pad(&buf, 23);
@@ -2768,14 +3146,14 @@
buf.Write(&num_classes);
// this_device_mode
- uint8_t tmp38;
- tmp38 = static_cast<uint8_t>(this_device_mode);
- buf.Write(&tmp38);
+ uint8_t tmp40;
+ tmp40 = static_cast<uint8_t>(this_device_mode);
+ buf.Write(&tmp40);
// other_device_mode
- uint8_t tmp39;
- tmp39 = static_cast<uint8_t>(other_device_mode);
- buf.Write(&tmp39);
+ uint8_t tmp41;
+ tmp41 = static_cast<uint8_t>(other_device_mode);
+ buf.Write(&tmp41);
// owner_events
buf.Write(&owner_events);
@@ -2838,9 +3216,9 @@
Read(&length, &buf);
// status
- uint8_t tmp40;
- Read(&tmp40, &buf);
- status = static_cast<GrabStatus>(tmp40);
+ uint8_t tmp42;
+ Read(&tmp42, &buf);
+ status = static_cast<GrabStatus>(tmp42);
// pad0
Pad(&buf, 23);
@@ -2928,9 +3306,9 @@
buf.Write(&num_classes);
// modifiers
- uint16_t tmp41;
- tmp41 = static_cast<uint16_t>(modifiers);
- buf.Write(&tmp41);
+ uint16_t tmp43;
+ tmp43 = static_cast<uint16_t>(modifiers);
+ buf.Write(&tmp43);
// modifier_device
buf.Write(&modifier_device);
@@ -2942,14 +3320,14 @@
buf.Write(&key);
// this_device_mode
- uint8_t tmp42;
- tmp42 = static_cast<uint8_t>(this_device_mode);
- buf.Write(&tmp42);
+ uint8_t tmp44;
+ tmp44 = static_cast<uint8_t>(this_device_mode);
+ buf.Write(&tmp44);
// other_device_mode
- uint8_t tmp43;
- tmp43 = static_cast<uint8_t>(other_device_mode);
- buf.Write(&tmp43);
+ uint8_t tmp45;
+ tmp45 = static_cast<uint8_t>(other_device_mode);
+ buf.Write(&tmp45);
// owner_events
buf.Write(&owner_events);
@@ -3012,9 +3390,9 @@
buf.Write(&grabWindow);
// modifiers
- uint16_t tmp44;
- tmp44 = static_cast<uint16_t>(modifiers);
- buf.Write(&tmp44);
+ uint16_t tmp46;
+ tmp46 = static_cast<uint16_t>(modifiers);
+ buf.Write(&tmp46);
// modifier_device
buf.Write(&modifier_device);
@@ -3084,19 +3462,19 @@
buf.Write(&num_classes);
// modifiers
- uint16_t tmp45;
- tmp45 = static_cast<uint16_t>(modifiers);
- buf.Write(&tmp45);
+ uint16_t tmp47;
+ tmp47 = static_cast<uint16_t>(modifiers);
+ buf.Write(&tmp47);
// this_device_mode
- uint8_t tmp46;
- tmp46 = static_cast<uint8_t>(this_device_mode);
- buf.Write(&tmp46);
+ uint8_t tmp48;
+ tmp48 = static_cast<uint8_t>(this_device_mode);
+ buf.Write(&tmp48);
// other_device_mode
- uint8_t tmp47;
- tmp47 = static_cast<uint8_t>(other_device_mode);
- buf.Write(&tmp47);
+ uint8_t tmp49;
+ tmp49 = static_cast<uint8_t>(other_device_mode);
+ buf.Write(&tmp49);
// button
buf.Write(&button);
@@ -3162,9 +3540,9 @@
buf.Write(&grab_window);
// modifiers
- uint16_t tmp48;
- tmp48 = static_cast<uint16_t>(modifiers);
- buf.Write(&tmp48);
+ uint16_t tmp50;
+ tmp50 = static_cast<uint16_t>(modifiers);
+ buf.Write(&tmp50);
// modifier_device
buf.Write(&modifier_device);
@@ -3220,9 +3598,9 @@
buf.Write(&time);
// mode
- uint8_t tmp49;
- tmp49 = static_cast<uint8_t>(mode);
- buf.Write(&tmp49);
+ uint8_t tmp51;
+ tmp51 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp51);
// device_id
buf.Write(&device_id);
@@ -3315,9 +3693,9 @@
Read(&time, &buf);
// revert_to
- uint8_t tmp50;
- Read(&tmp50, &buf);
- revert_to = static_cast<InputFocus>(tmp50);
+ uint8_t tmp52;
+ Read(&tmp52, &buf);
+ revert_to = static_cast<InputFocus>(tmp52);
// pad0
Pad(&buf, 15);
@@ -3359,9 +3737,9 @@
buf.Write(&time);
// revert_to
- uint8_t tmp51;
- tmp51 = static_cast<uint8_t>(revert_to);
- buf.Write(&tmp51);
+ uint8_t tmp53;
+ tmp53 = static_cast<uint8_t>(revert_to);
+ buf.Write(&tmp53);
// device_id
buf.Write(&device_id);
@@ -3464,9 +3842,9 @@
auto& data = feedbacks_elem;
// class_id
- uint8_t tmp52;
- Read(&tmp52, &buf);
- class_id = static_cast<Input::FeedbackClass>(tmp52);
+ uint8_t tmp54;
+ Read(&tmp54, &buf);
+ class_id = static_cast<Input::FeedbackClass>(tmp54);
// feedback_id
Read(&feedback_id, &buf);
@@ -3634,9 +4012,9 @@
Pad(&buf, sizeof(uint16_t));
// mask
- uint32_t tmp53;
- tmp53 = static_cast<uint32_t>(mask);
- buf.Write(&tmp53);
+ uint32_t tmp55;
+ tmp55 = static_cast<uint32_t>(mask);
+ buf.Write(&tmp55);
// device_id
buf.Write(&device_id);
@@ -3664,9 +4042,9 @@
&class_id);
SwitchVar(FeedbackClass::Led, data.led.has_value(), false, &class_id);
SwitchVar(FeedbackClass::Bell, data.bell.has_value(), false, &class_id);
- uint8_t tmp54;
- tmp54 = static_cast<uint8_t>(class_id);
- buf.Write(&tmp54);
+ uint8_t tmp56;
+ tmp56 = static_cast<uint8_t>(class_id);
+ buf.Write(&tmp56);
// feedback_id
buf.Write(&feedback_id);
@@ -4116,9 +4494,9 @@
Read(&length, &buf);
// status
- uint8_t tmp55;
- Read(&tmp55, &buf);
- status = static_cast<MappingStatus>(tmp55);
+ uint8_t tmp57;
+ Read(&tmp57, &buf);
+ status = static_cast<MappingStatus>(tmp57);
// pad0
Pad(&buf, 23);
@@ -4297,9 +4675,9 @@
Read(&length, &buf);
// status
- uint8_t tmp56;
- Read(&tmp56, &buf);
- status = static_cast<MappingStatus>(tmp56);
+ uint8_t tmp58;
+ Read(&tmp58, &buf);
+ status = static_cast<MappingStatus>(tmp58);
// pad0
Pad(&buf, 23);
@@ -4391,9 +4769,9 @@
auto& data = classes_elem;
// class_id
- uint8_t tmp57;
- Read(&tmp57, &buf);
- class_id = static_cast<Input::InputClass>(tmp57);
+ uint8_t tmp59;
+ Read(&tmp59, &buf);
+ class_id = static_cast<Input::InputClass>(tmp59);
// len
Read(&len, &buf);
@@ -4447,9 +4825,9 @@
Read(&num_valuators, &buf);
// mode
- uint8_t tmp58;
- Read(&tmp58, &buf);
- mode = static_cast<Input::ValuatorStateModeMask>(tmp58);
+ uint8_t tmp60;
+ Read(&tmp60, &buf);
+ mode = static_cast<Input::ValuatorStateModeMask>(tmp60);
// valuators
valuators.resize(num_valuators);
@@ -4600,9 +4978,9 @@
Read(&length, &buf);
// status
- uint8_t tmp59;
- Read(&tmp59, &buf);
- status = static_cast<GrabStatus>(tmp59);
+ uint8_t tmp61;
+ Read(&tmp61, &buf);
+ status = static_cast<GrabStatus>(tmp61);
// pad0
Pad(&buf, 23);
@@ -4636,9 +5014,9 @@
Pad(&buf, sizeof(uint16_t));
// control_id
- uint16_t tmp60;
- tmp60 = static_cast<uint16_t>(control_id);
- buf.Write(&tmp60);
+ uint16_t tmp62;
+ tmp62 = static_cast<uint16_t>(control_id);
+ buf.Write(&tmp62);
// device_id
buf.Write(&device_id);
@@ -4698,9 +5076,9 @@
auto& data = control;
// control_id
- uint16_t tmp61;
- Read(&tmp61, &buf);
- control_id = static_cast<Input::DeviceControl>(tmp61);
+ uint16_t tmp63;
+ Read(&tmp63, &buf);
+ control_id = static_cast<Input::DeviceControl>(tmp63);
// len
Read(&len, &buf);
@@ -4859,9 +5237,9 @@
Pad(&buf, sizeof(uint16_t));
// control_id
- uint16_t tmp62;
- tmp62 = static_cast<uint16_t>(control_id);
- buf.Write(&tmp62);
+ uint16_t tmp64;
+ tmp64 = static_cast<uint16_t>(control_id);
+ buf.Write(&tmp64);
// device_id
buf.Write(&device_id);
@@ -4885,9 +5263,9 @@
&control_id);
SwitchVar(DeviceControl::abs_area, data.abs_area.has_value(), false,
&control_id);
- uint16_t tmp63;
- tmp63 = static_cast<uint16_t>(control_id);
- buf.Write(&tmp63);
+ uint16_t tmp65;
+ tmp65 = static_cast<uint16_t>(control_id);
+ buf.Write(&tmp65);
// len
buf.Write(&len);
@@ -5173,14 +5551,14 @@
SwitchVar(PropertyFormat::c_8Bits, items.data8.has_value(), false, &format);
SwitchVar(PropertyFormat::c_16Bits, items.data16.has_value(), false, &format);
SwitchVar(PropertyFormat::c_32Bits, items.data32.has_value(), false, &format);
- uint8_t tmp64;
- tmp64 = static_cast<uint8_t>(format);
- buf.Write(&tmp64);
+ uint8_t tmp66;
+ tmp66 = static_cast<uint8_t>(format);
+ buf.Write(&tmp66);
// mode
- uint8_t tmp65;
- tmp65 = static_cast<uint8_t>(mode);
- buf.Write(&tmp65);
+ uint8_t tmp67;
+ tmp67 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp67);
// pad0
Pad(&buf, 1);
@@ -5396,9 +5774,9 @@
Read(&num_items, &buf);
// format
- uint8_t tmp66;
- Read(&tmp66, &buf);
- format = static_cast<Input::PropertyFormat>(tmp66);
+ uint8_t tmp68;
+ Read(&tmp68, &buf);
+ format = static_cast<Input::PropertyFormat>(tmp68);
// device_id
Read(&device_id, &buf);
@@ -5786,9 +6164,9 @@
false, &type);
SwitchVar(HierarchyChangeType::DetachSlave, data.detach_slave.has_value(),
false, &type);
- uint16_t tmp67;
- tmp67 = static_cast<uint16_t>(type);
- buf.Write(&tmp67);
+ uint16_t tmp69;
+ tmp69 = static_cast<uint16_t>(type);
+ buf.Write(&tmp69);
// len
buf.Write(&len);
@@ -5831,9 +6209,9 @@
buf.Write(&deviceid);
// return_mode
- uint8_t tmp68;
- tmp68 = static_cast<uint8_t>(return_mode);
- buf.Write(&tmp68);
+ uint8_t tmp70;
+ tmp70 = static_cast<uint8_t>(return_mode);
+ buf.Write(&tmp70);
// pad1
Pad(&buf, 1);
@@ -6052,9 +6430,9 @@
DCHECK_EQ(static_cast<size_t>(mask_len), mask.size());
for (auto& mask_elem : mask) {
// mask_elem
- uint32_t tmp69;
- tmp69 = static_cast<uint32_t>(mask_elem);
- buf.Write(&tmp69);
+ uint32_t tmp71;
+ tmp71 = static_cast<uint32_t>(mask_elem);
+ buf.Write(&tmp71);
}
}
}
@@ -6239,9 +6617,9 @@
Read(&deviceid, &buf);
// type
- uint16_t tmp70;
- Read(&tmp70, &buf);
- type = static_cast<Input::DeviceType>(tmp70);
+ uint16_t tmp72;
+ Read(&tmp72, &buf);
+ type = static_cast<Input::DeviceType>(tmp72);
// attachment
Read(&attachment, &buf);
@@ -6279,9 +6657,9 @@
auto& data = classes_elem;
// type
- uint16_t tmp71;
- Read(&tmp71, &buf);
- type = static_cast<Input::DeviceClassType>(tmp71);
+ uint16_t tmp73;
+ Read(&tmp73, &buf);
+ type = static_cast<Input::DeviceClassType>(tmp73);
// len
Read(&len, &buf);
@@ -6388,9 +6766,9 @@
Read(&resolution, &buf);
// mode
- uint8_t tmp72;
- Read(&tmp72, &buf);
- mode = static_cast<Input::ValuatorMode>(tmp72);
+ uint8_t tmp74;
+ Read(&tmp74, &buf);
+ mode = static_cast<Input::ValuatorMode>(tmp74);
// pad0
Pad(&buf, 3);
@@ -6406,17 +6784,17 @@
Read(&number, &buf);
// scroll_type
- uint16_t tmp73;
- Read(&tmp73, &buf);
- scroll_type = static_cast<Input::ScrollType>(tmp73);
+ uint16_t tmp75;
+ Read(&tmp75, &buf);
+ scroll_type = static_cast<Input::ScrollType>(tmp75);
// pad1
Pad(&buf, 2);
// flags
- uint32_t tmp74;
- Read(&tmp74, &buf);
- flags = static_cast<Input::ScrollFlags>(tmp74);
+ uint32_t tmp76;
+ Read(&tmp76, &buf);
+ flags = static_cast<Input::ScrollFlags>(tmp76);
// increment
{
@@ -6436,13 +6814,23 @@
auto& num_touches = (*data.touch).num_touches;
// mode
- uint8_t tmp75;
- Read(&tmp75, &buf);
- mode = static_cast<Input::TouchMode>(tmp75);
+ uint8_t tmp77;
+ Read(&tmp77, &buf);
+ mode = static_cast<Input::TouchMode>(tmp77);
// num_touches
Read(&num_touches, &buf);
}
+ if (CaseEq(data_expr, Input::DeviceClassType::Gesture)) {
+ data.gesture.emplace();
+ auto& num_touches = (*data.gesture).num_touches;
+
+ // num_touches
+ Read(&num_touches, &buf);
+
+ // pad2
+ Pad(&buf, 1);
+ }
}
}
}
@@ -6614,19 +7002,19 @@
buf.Write(&deviceid);
// mode
- uint8_t tmp76;
- tmp76 = static_cast<uint8_t>(mode);
- buf.Write(&tmp76);
+ uint8_t tmp78;
+ tmp78 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp78);
// paired_device_mode
- uint8_t tmp77;
- tmp77 = static_cast<uint8_t>(paired_device_mode);
- buf.Write(&tmp77);
+ uint8_t tmp79;
+ tmp79 = static_cast<uint8_t>(paired_device_mode);
+ buf.Write(&tmp79);
// owner_events
- uint8_t tmp78;
- tmp78 = static_cast<uint8_t>(owner_events);
- buf.Write(&tmp78);
+ uint8_t tmp80;
+ tmp80 = static_cast<uint8_t>(owner_events);
+ buf.Write(&tmp80);
// pad0
Pad(&buf, 1);
@@ -6687,9 +7075,9 @@
Read(&length, &buf);
// status
- uint8_t tmp79;
- Read(&tmp79, &buf);
- status = static_cast<GrabStatus>(tmp79);
+ uint8_t tmp81;
+ Read(&tmp81, &buf);
+ status = static_cast<GrabStatus>(tmp81);
// pad1
Pad(&buf, 23);
@@ -6771,9 +7159,9 @@
buf.Write(&deviceid);
// event_mode
- uint8_t tmp80;
- tmp80 = static_cast<uint8_t>(event_mode);
- buf.Write(&tmp80);
+ uint8_t tmp82;
+ tmp82 = static_cast<uint8_t>(event_mode);
+ buf.Write(&tmp82);
// pad0
Pad(&buf, 1);
@@ -6856,25 +7244,25 @@
buf.Write(&mask_len);
// grab_type
- uint8_t tmp81;
- tmp81 = static_cast<uint8_t>(grab_type);
- buf.Write(&tmp81);
-
- // grab_mode
- uint8_t tmp82;
- tmp82 = static_cast<uint8_t>(grab_mode);
- buf.Write(&tmp82);
-
- // paired_device_mode
uint8_t tmp83;
- tmp83 = static_cast<uint8_t>(paired_device_mode);
+ tmp83 = static_cast<uint8_t>(grab_type);
buf.Write(&tmp83);
- // owner_events
+ // grab_mode
uint8_t tmp84;
- tmp84 = static_cast<uint8_t>(owner_events);
+ tmp84 = static_cast<uint8_t>(grab_mode);
buf.Write(&tmp84);
+ // paired_device_mode
+ uint8_t tmp85;
+ tmp85 = static_cast<uint8_t>(paired_device_mode);
+ buf.Write(&tmp85);
+
+ // owner_events
+ uint8_t tmp86;
+ tmp86 = static_cast<uint8_t>(owner_events);
+ buf.Write(&tmp86);
+
// pad0
Pad(&buf, 2);
@@ -6959,9 +7347,9 @@
Read(&modifiers, &buf);
// status
- uint8_t tmp85;
- Read(&tmp85, &buf);
- status = static_cast<GrabStatus>(tmp85);
+ uint8_t tmp87;
+ Read(&tmp87, &buf);
+ status = static_cast<GrabStatus>(tmp87);
// pad0
Pad(&buf, 3);
@@ -7015,9 +7403,9 @@
buf.Write(&num_modifiers);
// grab_type
- uint8_t tmp86;
- tmp86 = static_cast<uint8_t>(grab_type);
- buf.Write(&tmp86);
+ uint8_t tmp88;
+ tmp88 = static_cast<uint8_t>(grab_type);
+ buf.Write(&tmp88);
// pad0
Pad(&buf, 3);
@@ -7159,17 +7547,17 @@
buf.Write(&deviceid);
// mode
- uint8_t tmp87;
- tmp87 = static_cast<uint8_t>(mode);
- buf.Write(&tmp87);
+ uint8_t tmp89;
+ tmp89 = static_cast<uint8_t>(mode);
+ buf.Write(&tmp89);
// format
SwitchVar(PropertyFormat::c_8Bits, items.data8.has_value(), false, &format);
SwitchVar(PropertyFormat::c_16Bits, items.data16.has_value(), false, &format);
SwitchVar(PropertyFormat::c_32Bits, items.data32.has_value(), false, &format);
- uint8_t tmp88;
- tmp88 = static_cast<uint8_t>(format);
- buf.Write(&tmp88);
+ uint8_t tmp90;
+ tmp90 = static_cast<uint8_t>(format);
+ buf.Write(&tmp90);
// property
buf.Write(&property);
@@ -7383,9 +7771,9 @@
Read(&num_items, &buf);
// format
- uint8_t tmp89;
- Read(&tmp89, &buf);
- format = static_cast<Input::PropertyFormat>(tmp89);
+ uint8_t tmp91;
+ Read(&tmp91, &buf);
+ format = static_cast<Input::PropertyFormat>(tmp91);
// pad1
Pad(&buf, 11);
@@ -7527,9 +7915,9 @@
mask.resize(mask_len);
for (auto& mask_elem : mask) {
// mask_elem
- uint32_t tmp90;
- Read(&tmp90, &buf);
- mask_elem = static_cast<Input::XIEventMask>(tmp90);
+ uint32_t tmp92;
+ Read(&tmp92, &buf);
+ mask_elem = static_cast<Input::XIEventMask>(tmp92);
}
}
}
diff --git a/ui/gfx/x/generated_protos/xinput.h b/ui/gfx/x/generated_protos/xinput.h
index e522384..944b84c 100644
--- a/ui/gfx/x/generated_protos/xinput.h
+++ b/ui/gfx/x/generated_protos/xinput.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -70,7 +70,7 @@
class COMPONENT_EXPORT(X11) Input {
public:
static constexpr unsigned major_version = 2;
- static constexpr unsigned minor_version = 3;
+ static constexpr unsigned minor_version = 4;
Input(Connection* connection, const x11::QueryExtensionReply& info);
@@ -226,6 +226,7 @@
Valuator = 2,
Scroll = 3,
Touch = 8,
+ Gesture = 9,
};
enum class DeviceType : int {
@@ -279,6 +280,8 @@
Enter = 2,
FocusIn = 3,
TouchBegin = 4,
+ GesturePinchBegin = 5,
+ GestureSwipeBegin = 6,
};
enum class ModifierMask : int {
@@ -375,12 +378,30 @@
DeviceIsGrabbed = 1 << 1,
};
+ enum class GesturePinchEventFlags : int {
+ GesturePinchCancelled = 1 << 0,
+ };
+
+ enum class GestureSwipeEventFlags : int {
+ GestureSwipeCancelled = 1 << 0,
+ };
+
struct Fp3232 {
+ bool operator==(const Fp3232& other) const {
+ return integral == other.integral && frac == other.frac;
+ }
+
int32_t integral{};
uint32_t frac{};
};
struct DeviceInfo {
+ bool operator==(const DeviceInfo& other) const {
+ return device_type == other.device_type && device_id == other.device_id &&
+ num_class_info == other.num_class_info &&
+ device_use == other.device_use;
+ }
+
Atom device_type{};
uint8_t device_id{};
uint8_t num_class_info{};
@@ -388,6 +409,12 @@
};
struct KeyInfo {
+ bool operator==(const KeyInfo& other) const {
+ return class_id == other.class_id && len == other.len &&
+ min_keycode == other.min_keycode &&
+ max_keycode == other.max_keycode && num_keys == other.num_keys;
+ }
+
InputClass class_id{};
uint8_t len{};
KeyCode min_keycode{};
@@ -396,18 +423,34 @@
};
struct ButtonInfo {
+ bool operator==(const ButtonInfo& other) const {
+ return class_id == other.class_id && len == other.len &&
+ num_buttons == other.num_buttons;
+ }
+
InputClass class_id{};
uint8_t len{};
uint16_t num_buttons{};
};
struct AxisInfo {
+ bool operator==(const AxisInfo& other) const {
+ return resolution == other.resolution && minimum == other.minimum &&
+ maximum == other.maximum;
+ }
+
uint32_t resolution{};
int32_t minimum{};
int32_t maximum{};
};
struct ValuatorInfo {
+ bool operator==(const ValuatorInfo& other) const {
+ return class_id == other.class_id && len == other.len &&
+ mode == other.mode && motion_size == other.motion_size &&
+ axes == other.axes;
+ }
+
InputClass class_id{};
uint8_t len{};
ValuatorMode mode{};
@@ -436,20 +479,43 @@
};
struct DeviceName {
+ bool operator==(const DeviceName& other) const {
+ return string == other.string;
+ }
+
std::string string{};
};
struct InputClassInfo {
+ bool operator==(const InputClassInfo& other) const {
+ return class_id == other.class_id &&
+ event_type_base == other.event_type_base;
+ }
+
InputClass class_id{};
EventTypeBase event_type_base{};
};
struct DeviceTimeCoord {
+ bool operator==(const DeviceTimeCoord& other) const {
+ return time == other.time && axisvalues == other.axisvalues;
+ }
+
Time time{};
std::vector<int32_t> axisvalues{};
};
struct KbdFeedbackState {
+ bool operator==(const KbdFeedbackState& other) const {
+ return class_id == other.class_id && feedback_id == other.feedback_id &&
+ len == other.len && pitch == other.pitch &&
+ duration == other.duration && led_mask == other.led_mask &&
+ led_values == other.led_values &&
+ global_auto_repeat == other.global_auto_repeat &&
+ click == other.click && percent == other.percent &&
+ auto_repeats == other.auto_repeats;
+ }
+
FeedbackClass class_id{};
uint8_t feedback_id{};
uint16_t len{};
@@ -464,6 +530,12 @@
};
struct PtrFeedbackState {
+ bool operator==(const PtrFeedbackState& other) const {
+ return class_id == other.class_id && feedback_id == other.feedback_id &&
+ len == other.len && accel_num == other.accel_num &&
+ accel_denom == other.accel_denom && threshold == other.threshold;
+ }
+
FeedbackClass class_id{};
uint8_t feedback_id{};
uint16_t len{};
@@ -473,6 +545,12 @@
};
struct IntegerFeedbackState {
+ bool operator==(const IntegerFeedbackState& other) const {
+ return class_id == other.class_id && feedback_id == other.feedback_id &&
+ len == other.len && resolution == other.resolution &&
+ min_value == other.min_value && max_value == other.max_value;
+ }
+
FeedbackClass class_id{};
uint8_t feedback_id{};
uint16_t len{};
@@ -482,6 +560,12 @@
};
struct StringFeedbackState {
+ bool operator==(const StringFeedbackState& other) const {
+ return class_id == other.class_id && feedback_id == other.feedback_id &&
+ len == other.len && max_symbols == other.max_symbols &&
+ keysyms == other.keysyms;
+ }
+
FeedbackClass class_id{};
uint8_t feedback_id{};
uint16_t len{};
@@ -490,6 +574,12 @@
};
struct BellFeedbackState {
+ bool operator==(const BellFeedbackState& other) const {
+ return class_id == other.class_id && feedback_id == other.feedback_id &&
+ len == other.len && percent == other.percent &&
+ pitch == other.pitch && duration == other.duration;
+ }
+
FeedbackClass class_id{};
uint8_t feedback_id{};
uint16_t len{};
@@ -499,6 +589,12 @@
};
struct LedFeedbackState {
+ bool operator==(const LedFeedbackState& other) const {
+ return class_id == other.class_id && feedback_id == other.feedback_id &&
+ len == other.len && led_mask == other.led_mask &&
+ led_values == other.led_values;
+ }
+
FeedbackClass class_id{};
uint8_t feedback_id{};
uint16_t len{};
@@ -551,6 +647,17 @@
};
struct KbdFeedbackCtl {
+ bool operator==(const KbdFeedbackCtl& other) const {
+ return class_id == other.class_id && feedback_id == other.feedback_id &&
+ len == other.len && key == other.key &&
+ auto_repeat_mode == other.auto_repeat_mode &&
+ key_click_percent == other.key_click_percent &&
+ bell_percent == other.bell_percent &&
+ bell_pitch == other.bell_pitch &&
+ bell_duration == other.bell_duration &&
+ led_mask == other.led_mask && led_values == other.led_values;
+ }
+
FeedbackClass class_id{};
uint8_t feedback_id{};
uint16_t len{};
@@ -565,6 +672,12 @@
};
struct PtrFeedbackCtl {
+ bool operator==(const PtrFeedbackCtl& other) const {
+ return class_id == other.class_id && feedback_id == other.feedback_id &&
+ len == other.len && num == other.num && denom == other.denom &&
+ threshold == other.threshold;
+ }
+
FeedbackClass class_id{};
uint8_t feedback_id{};
uint16_t len{};
@@ -574,6 +687,11 @@
};
struct IntegerFeedbackCtl {
+ bool operator==(const IntegerFeedbackCtl& other) const {
+ return class_id == other.class_id && feedback_id == other.feedback_id &&
+ len == other.len && int_to_display == other.int_to_display;
+ }
+
FeedbackClass class_id{};
uint8_t feedback_id{};
uint16_t len{};
@@ -581,6 +699,11 @@
};
struct StringFeedbackCtl {
+ bool operator==(const StringFeedbackCtl& other) const {
+ return class_id == other.class_id && feedback_id == other.feedback_id &&
+ len == other.len && keysyms == other.keysyms;
+ }
+
FeedbackClass class_id{};
uint8_t feedback_id{};
uint16_t len{};
@@ -588,6 +711,12 @@
};
struct BellFeedbackCtl {
+ bool operator==(const BellFeedbackCtl& other) const {
+ return class_id == other.class_id && feedback_id == other.feedback_id &&
+ len == other.len && percent == other.percent &&
+ pitch == other.pitch && duration == other.duration;
+ }
+
FeedbackClass class_id{};
uint8_t feedback_id{};
uint16_t len{};
@@ -597,6 +726,12 @@
};
struct LedFeedbackCtl {
+ bool operator==(const LedFeedbackCtl& other) const {
+ return class_id == other.class_id && feedback_id == other.feedback_id &&
+ len == other.len && led_mask == other.led_mask &&
+ led_values == other.led_values;
+ }
+
FeedbackClass class_id{};
uint8_t feedback_id{};
uint16_t len{};
@@ -646,6 +781,11 @@
};
struct KeyState {
+ bool operator==(const KeyState& other) const {
+ return class_id == other.class_id && len == other.len &&
+ num_keys == other.num_keys && keys == other.keys;
+ }
+
InputClass class_id{};
uint8_t len{};
uint8_t num_keys{};
@@ -653,6 +793,11 @@
};
struct ButtonState {
+ bool operator==(const ButtonState& other) const {
+ return class_id == other.class_id && len == other.len &&
+ num_buttons == other.num_buttons && buttons == other.buttons;
+ }
+
InputClass class_id{};
uint8_t len{};
uint8_t num_buttons{};
@@ -660,6 +805,11 @@
};
struct ValuatorState {
+ bool operator==(const ValuatorState& other) const {
+ return class_id == other.class_id && len == other.len &&
+ mode == other.mode && valuators == other.valuators;
+ }
+
InputClass class_id{};
uint8_t len{};
ValuatorStateModeMask mode{};
@@ -686,6 +836,13 @@
};
struct DeviceResolutionState {
+ bool operator==(const DeviceResolutionState& other) const {
+ return control_id == other.control_id && len == other.len &&
+ resolution_values == other.resolution_values &&
+ resolution_min == other.resolution_min &&
+ resolution_max == other.resolution_max;
+ }
+
DeviceControl control_id{};
uint16_t len{};
std::vector<uint32_t> resolution_values{};
@@ -694,6 +851,15 @@
};
struct DeviceAbsCalibState {
+ bool operator==(const DeviceAbsCalibState& other) const {
+ return control_id == other.control_id && len == other.len &&
+ min_x == other.min_x && max_x == other.max_x &&
+ min_y == other.min_y && max_y == other.max_y &&
+ flip_x == other.flip_x && flip_y == other.flip_y &&
+ rotation == other.rotation &&
+ button_threshold == other.button_threshold;
+ }
+
DeviceControl control_id{};
uint16_t len{};
int32_t min_x{};
@@ -707,6 +873,13 @@
};
struct DeviceAbsAreaState {
+ bool operator==(const DeviceAbsAreaState& other) const {
+ return control_id == other.control_id && len == other.len &&
+ offset_x == other.offset_x && offset_y == other.offset_y &&
+ width == other.width && height == other.height &&
+ screen == other.screen && following == other.following;
+ }
+
DeviceControl control_id{};
uint16_t len{};
uint32_t offset_x{};
@@ -718,6 +891,11 @@
};
struct DeviceCoreState {
+ bool operator==(const DeviceCoreState& other) const {
+ return control_id == other.control_id && len == other.len &&
+ status == other.status && iscore == other.iscore;
+ }
+
DeviceControl control_id{};
uint16_t len{};
uint8_t status{};
@@ -725,6 +903,11 @@
};
struct DeviceEnableState {
+ bool operator==(const DeviceEnableState& other) const {
+ return control_id == other.control_id && len == other.len &&
+ enable == other.enable;
+ }
+
DeviceControl control_id{};
uint16_t len{};
uint8_t enable{};
@@ -770,6 +953,12 @@
};
struct DeviceResolutionCtl {
+ bool operator==(const DeviceResolutionCtl& other) const {
+ return control_id == other.control_id && len == other.len &&
+ first_valuator == other.first_valuator &&
+ resolution_values == other.resolution_values;
+ }
+
DeviceControl control_id{};
uint16_t len{};
uint8_t first_valuator{};
@@ -777,6 +966,15 @@
};
struct DeviceAbsCalibCtl {
+ bool operator==(const DeviceAbsCalibCtl& other) const {
+ return control_id == other.control_id && len == other.len &&
+ min_x == other.min_x && max_x == other.max_x &&
+ min_y == other.min_y && max_y == other.max_y &&
+ flip_x == other.flip_x && flip_y == other.flip_y &&
+ rotation == other.rotation &&
+ button_threshold == other.button_threshold;
+ }
+
DeviceControl control_id{};
uint16_t len{};
int32_t min_x{};
@@ -790,6 +988,13 @@
};
struct DeviceAbsAreaCtrl {
+ bool operator==(const DeviceAbsAreaCtrl& other) const {
+ return control_id == other.control_id && len == other.len &&
+ offset_x == other.offset_x && offset_y == other.offset_y &&
+ width == other.width && height == other.height &&
+ screen == other.screen && following == other.following;
+ }
+
DeviceControl control_id{};
uint16_t len{};
uint32_t offset_x{};
@@ -801,12 +1006,22 @@
};
struct DeviceCoreCtrl {
+ bool operator==(const DeviceCoreCtrl& other) const {
+ return control_id == other.control_id && len == other.len &&
+ status == other.status;
+ }
+
DeviceControl control_id{};
uint16_t len{};
uint8_t status{};
};
struct DeviceEnableCtrl {
+ bool operator==(const DeviceEnableCtrl& other) const {
+ return control_id == other.control_id && len == other.len &&
+ enable == other.enable;
+ }
+
DeviceControl control_id{};
uint16_t len{};
uint8_t enable{};
@@ -850,6 +1065,11 @@
};
struct GroupInfo {
+ bool operator==(const GroupInfo& other) const {
+ return base == other.base && latched == other.latched &&
+ locked == other.locked && effective == other.effective;
+ }
+
uint8_t base{};
uint8_t latched{};
uint8_t locked{};
@@ -857,6 +1077,11 @@
};
struct ModifierInfo {
+ bool operator==(const ModifierInfo& other) const {
+ return base == other.base && latched == other.latched &&
+ locked == other.locked && effective == other.effective;
+ }
+
uint32_t base{};
uint32_t latched{};
uint32_t locked{};
@@ -864,6 +1089,12 @@
};
struct AddMaster {
+ bool operator==(const AddMaster& other) const {
+ return type == other.type && len == other.len &&
+ send_core == other.send_core && enable == other.enable &&
+ name == other.name;
+ }
+
HierarchyChangeType type{};
uint16_t len{};
uint8_t send_core{};
@@ -872,6 +1103,13 @@
};
struct RemoveMaster {
+ bool operator==(const RemoveMaster& other) const {
+ return type == other.type && len == other.len &&
+ deviceid == other.deviceid && return_mode == other.return_mode &&
+ return_pointer == other.return_pointer &&
+ return_keyboard == other.return_keyboard;
+ }
+
HierarchyChangeType type{};
uint16_t len{};
DeviceId deviceid{};
@@ -881,6 +1119,11 @@
};
struct AttachSlave {
+ bool operator==(const AttachSlave& other) const {
+ return type == other.type && len == other.len &&
+ deviceid == other.deviceid && master == other.master;
+ }
+
HierarchyChangeType type{};
uint16_t len{};
DeviceId deviceid{};
@@ -888,6 +1131,11 @@
};
struct DetachSlave {
+ bool operator==(const DetachSlave& other) const {
+ return type == other.type && len == other.len &&
+ deviceid == other.deviceid;
+ }
+
HierarchyChangeType type{};
uint16_t len{};
DeviceId deviceid{};
@@ -920,11 +1168,21 @@
};
struct EventMask {
+ bool operator==(const EventMask& other) const {
+ return deviceid == other.deviceid && mask == other.mask;
+ }
+
DeviceId deviceid{};
std::vector<XIEventMask> mask{};
};
struct ButtonClass {
+ bool operator==(const ButtonClass& other) const {
+ return type == other.type && len == other.len &&
+ sourceid == other.sourceid && state == other.state &&
+ labels == other.labels;
+ }
+
DeviceClassType type{};
uint16_t len{};
DeviceId sourceid{};
@@ -933,6 +1191,11 @@
};
struct KeyClass {
+ bool operator==(const KeyClass& other) const {
+ return type == other.type && len == other.len &&
+ sourceid == other.sourceid && keys == other.keys;
+ }
+
DeviceClassType type{};
uint16_t len{};
DeviceId sourceid{};
@@ -940,6 +1203,13 @@
};
struct ScrollClass {
+ bool operator==(const ScrollClass& other) const {
+ return type == other.type && len == other.len &&
+ sourceid == other.sourceid && number == other.number &&
+ scroll_type == other.scroll_type && flags == other.flags &&
+ increment == other.increment;
+ }
+
DeviceClassType type{};
uint16_t len{};
DeviceId sourceid{};
@@ -950,6 +1220,12 @@
};
struct TouchClass {
+ bool operator==(const TouchClass& other) const {
+ return type == other.type && len == other.len &&
+ sourceid == other.sourceid && mode == other.mode &&
+ num_touches == other.num_touches;
+ }
+
DeviceClassType type{};
uint16_t len{};
DeviceId sourceid{};
@@ -957,7 +1233,27 @@
uint8_t num_touches{};
};
+ struct GestureClass {
+ bool operator==(const GestureClass& other) const {
+ return type == other.type && len == other.len &&
+ sourceid == other.sourceid && num_touches == other.num_touches;
+ }
+
+ DeviceClassType type{};
+ uint16_t len{};
+ DeviceId sourceid{};
+ uint8_t num_touches{};
+ };
+
struct ValuatorClass {
+ bool operator==(const ValuatorClass& other) const {
+ return type == other.type && len == other.len &&
+ sourceid == other.sourceid && number == other.number &&
+ label == other.label && min == other.min && max == other.max &&
+ value == other.value && resolution == other.resolution &&
+ mode == other.mode;
+ }
+
DeviceClassType type{};
uint16_t len{};
DeviceId sourceid{};
@@ -999,11 +1295,15 @@
TouchMode mode{};
uint8_t num_touches{};
};
+ struct Gesture {
+ uint8_t num_touches{};
+ };
absl::optional<Key> key{};
absl::optional<Button> button{};
absl::optional<Valuator> valuator{};
absl::optional<Scroll> scroll{};
absl::optional<Touch> touch{};
+ absl::optional<Gesture> gesture{};
};
struct XIDeviceInfo {
@@ -1016,11 +1316,20 @@
};
struct GrabModifierInfo {
+ bool operator==(const GrabModifierInfo& other) const {
+ return modifiers == other.modifiers && status == other.status;
+ }
+
uint32_t modifiers{};
GrabStatus status{};
};
struct BarrierReleasePointerInfo {
+ bool operator==(const BarrierReleasePointerInfo& other) const {
+ return deviceid == other.deviceid && barrier == other.barrier &&
+ eventid == other.eventid;
+ }
+
DeviceId deviceid{};
XFixes::Barrier barrier{};
uint32_t eventid{};
@@ -1029,7 +1338,6 @@
struct DeviceValuatorEvent {
static constexpr int type_id = 20;
static constexpr uint8_t opcode = 0;
- bool send_event{};
uint8_t device_id{};
uint16_t sequence{};
uint16_t device_state{};
@@ -1051,7 +1359,6 @@
ProximityIn = 8,
ProximityOut = 9,
} opcode{};
- bool send_event{};
uint8_t detail{};
uint16_t sequence{};
Time time{};
@@ -1075,7 +1382,6 @@
In = 6,
Out = 7,
} opcode{};
- bool send_event{};
x11::NotifyDetail detail{};
uint16_t sequence{};
Time time{};
@@ -1089,7 +1395,6 @@
struct DeviceStateNotifyEvent {
static constexpr int type_id = 23;
static constexpr uint8_t opcode = 10;
- bool send_event{};
uint8_t device_id{};
uint16_t sequence{};
Time time{};
@@ -1107,7 +1412,6 @@
struct DeviceMappingNotifyEvent {
static constexpr int type_id = 24;
static constexpr uint8_t opcode = 11;
- bool send_event{};
uint8_t device_id{};
uint16_t sequence{};
Mapping request{};
@@ -1121,7 +1425,6 @@
struct ChangeDeviceNotifyEvent {
static constexpr int type_id = 25;
static constexpr uint8_t opcode = 12;
- bool send_event{};
uint8_t device_id{};
uint16_t sequence{};
Time time{};
@@ -1133,7 +1436,6 @@
struct DeviceKeyStateNotifyEvent {
static constexpr int type_id = 26;
static constexpr uint8_t opcode = 13;
- bool send_event{};
uint8_t device_id{};
uint16_t sequence{};
std::array<uint8_t, 28> keys{};
@@ -1144,7 +1446,6 @@
struct DeviceButtonStateNotifyEvent {
static constexpr int type_id = 27;
static constexpr uint8_t opcode = 14;
- bool send_event{};
uint8_t device_id{};
uint16_t sequence{};
std::array<uint8_t, 28> buttons{};
@@ -1155,7 +1456,6 @@
struct DevicePresenceNotifyEvent {
static constexpr int type_id = 28;
static constexpr uint8_t opcode = 15;
- bool send_event{};
uint16_t sequence{};
Time time{};
DeviceChange devchange{};
@@ -1168,7 +1468,6 @@
struct DevicePropertyNotifyEvent {
static constexpr int type_id = 29;
static constexpr uint8_t opcode = 16;
- bool send_event{};
Property state{};
uint16_t sequence{};
Time time{};
@@ -1181,7 +1480,6 @@
struct DeviceChangedEvent {
static constexpr int type_id = 30;
static constexpr uint8_t opcode = 1;
- bool send_event{};
uint16_t sequence{};
DeviceId deviceid{};
Time time{};
@@ -1204,7 +1502,6 @@
TouchUpdate = 19,
TouchEnd = 20,
} opcode{};
- bool send_event{};
uint16_t sequence{};
DeviceId deviceid{};
Time time{};
@@ -1235,7 +1532,6 @@
FocusIn = 9,
FocusOut = 10,
} opcode{};
- bool send_event{};
uint16_t sequence{};
DeviceId deviceid{};
Time time{};
@@ -1259,6 +1555,12 @@
};
struct HierarchyInfo {
+ bool operator==(const HierarchyInfo& other) const {
+ return deviceid == other.deviceid && attachment == other.attachment &&
+ type == other.type && enabled == other.enabled &&
+ flags == other.flags;
+ }
+
DeviceId deviceid{};
DeviceId attachment{};
DeviceType type{};
@@ -1269,7 +1571,6 @@
struct HierarchyEvent {
static constexpr int type_id = 33;
static constexpr uint8_t opcode = 11;
- bool send_event{};
uint16_t sequence{};
DeviceId deviceid{};
Time time{};
@@ -1282,7 +1583,6 @@
struct PropertyEvent {
static constexpr int type_id = 34;
static constexpr uint8_t opcode = 12;
- bool send_event{};
uint16_t sequence{};
DeviceId deviceid{};
Time time{};
@@ -1304,7 +1604,6 @@
RawTouchUpdate = 23,
RawTouchEnd = 24,
} opcode{};
- bool send_event{};
uint16_t sequence{};
DeviceId deviceid{};
Time time{};
@@ -1321,7 +1620,6 @@
struct TouchOwnershipEvent {
static constexpr int type_id = 36;
static constexpr uint8_t opcode = 21;
- bool send_event{};
uint16_t sequence{};
DeviceId deviceid{};
Time time{};
@@ -1341,7 +1639,6 @@
Hit = 25,
Leave = 26,
} opcode{};
- bool send_event{};
uint16_t sequence{};
DeviceId deviceid{};
Time time{};
@@ -1360,33 +1657,110 @@
x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
};
+ struct GesturePinchEvent {
+ static constexpr int type_id = 38;
+ enum Opcode {
+ Begin = 27,
+ Update = 28,
+ End = 29,
+ } opcode{};
+ uint16_t sequence{};
+ DeviceId deviceid{};
+ Time time{};
+ uint32_t detail{};
+ Window root{};
+ Window event{};
+ Window child{};
+ Fp1616 root_x{};
+ Fp1616 root_y{};
+ Fp1616 event_x{};
+ Fp1616 event_y{};
+ Fp1616 delta_x{};
+ Fp1616 delta_y{};
+ Fp1616 delta_unaccel_x{};
+ Fp1616 delta_unaccel_y{};
+ Fp1616 scale{};
+ Fp1616 delta_angle{};
+ DeviceId sourceid{};
+ ModifierInfo mods{};
+ GroupInfo group{};
+ GesturePinchEventFlags flags{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+ };
+
+ struct GestureSwipeEvent {
+ static constexpr int type_id = 39;
+ enum Opcode {
+ Begin = 30,
+ Update = 31,
+ End = 32,
+ } opcode{};
+ uint16_t sequence{};
+ DeviceId deviceid{};
+ Time time{};
+ uint32_t detail{};
+ Window root{};
+ Window event{};
+ Window child{};
+ Fp1616 root_x{};
+ Fp1616 root_y{};
+ Fp1616 event_x{};
+ Fp1616 event_y{};
+ Fp1616 delta_x{};
+ Fp1616 delta_y{};
+ Fp1616 delta_unaccel_x{};
+ Fp1616 delta_unaccel_y{};
+ DeviceId sourceid{};
+ ModifierInfo mods{};
+ GroupInfo group{};
+ GestureSwipeEventFlags flags{};
+
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+ };
+
using EventForSend = std::array<uint8_t, 32>;
struct DeviceError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct EventError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct ModeError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct DeviceBusyError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct ClassError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
@@ -3231,4 +3605,36 @@
static_cast<T>(r));
}
+inline constexpr x11::Input::GesturePinchEventFlags operator|(
+ x11::Input::GesturePinchEventFlags l,
+ x11::Input::GesturePinchEventFlags r) {
+ using T = std::underlying_type_t<x11::Input::GesturePinchEventFlags>;
+ return static_cast<x11::Input::GesturePinchEventFlags>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::GesturePinchEventFlags operator&(
+ x11::Input::GesturePinchEventFlags l,
+ x11::Input::GesturePinchEventFlags r) {
+ using T = std::underlying_type_t<x11::Input::GesturePinchEventFlags>;
+ return static_cast<x11::Input::GesturePinchEventFlags>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::GestureSwipeEventFlags operator|(
+ x11::Input::GestureSwipeEventFlags l,
+ x11::Input::GestureSwipeEventFlags r) {
+ using T = std::underlying_type_t<x11::Input::GestureSwipeEventFlags>;
+ return static_cast<x11::Input::GestureSwipeEventFlags>(static_cast<T>(l) |
+ static_cast<T>(r));
+}
+
+inline constexpr x11::Input::GestureSwipeEventFlags operator&(
+ x11::Input::GestureSwipeEventFlags l,
+ x11::Input::GestureSwipeEventFlags r) {
+ using T = std::underlying_type_t<x11::Input::GestureSwipeEventFlags>;
+ return static_cast<x11::Input::GestureSwipeEventFlags>(static_cast<T>(l) &
+ static_cast<T>(r));
+}
+
#endif // UI_GFX_X_GENERATED_PROTOS_XINPUT_H_
diff --git a/ui/gfx/x/generated_protos/xkb.cc b/ui/gfx/x/generated_protos/xkb.cc
index e623c97..3423d8b 100644
--- a/ui/gfx/x/generated_protos/xkb.cc
+++ b/ui/gfx/x/generated_protos/xkb.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "xkb.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/xkb.h b/ui/gfx/x/generated_protos/xkb.h
index 7346ca1..89ea61e 100644
--- a/ui/gfx/x/generated_protos/xkb.h
+++ b/ui/gfx/x/generated_protos/xkb.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -525,6 +525,13 @@
};
struct IndicatorMap {
+ bool operator==(const IndicatorMap& other) const {
+ return flags == other.flags && whichGroups == other.whichGroups &&
+ groups == other.groups && whichMods == other.whichMods &&
+ mods == other.mods && realMods == other.realMods &&
+ vmods == other.vmods && ctrls == other.ctrls;
+ }
+
IMFlag flags{};
IMGroupsWhich whichGroups{};
SetOfGroup groups{};
@@ -536,26 +543,47 @@
};
struct ModDef {
+ bool operator==(const ModDef& other) const {
+ return mask == other.mask && realMods == other.realMods &&
+ vmods == other.vmods;
+ }
+
ModMask mask{};
ModMask realMods{};
VMod vmods{};
};
struct KeyName {
+ bool operator==(const KeyName& other) const { return name == other.name; }
+
std::array<char, 4> name{};
};
struct KeyAlias {
+ bool operator==(const KeyAlias& other) const {
+ return real == other.real && alias == other.alias;
+ }
+
std::array<char, 4> real{};
std::array<char, 4> alias{};
};
struct CountedString16 {
+ bool operator==(const CountedString16& other) const {
+ return string == other.string && alignment_pad == other.alignment_pad;
+ }
+
std::string string{};
scoped_refptr<base::RefCountedMemory> alignment_pad{};
};
struct KTMapEntry {
+ bool operator==(const KTMapEntry& other) const {
+ return active == other.active && mods_mask == other.mods_mask &&
+ level == other.level && mods_mods == other.mods_mods &&
+ mods_vmods == other.mods_vmods;
+ }
+
uint8_t active{};
ModMask mods_mask{};
uint8_t level{};
@@ -564,6 +592,13 @@
};
struct KeyType {
+ bool operator==(const KeyType& other) const {
+ return mods_mask == other.mods_mask && mods_mods == other.mods_mods &&
+ mods_vmods == other.mods_vmods && numLevels == other.numLevels &&
+ hasPreserve == other.hasPreserve && map == other.map &&
+ preserve == other.preserve;
+ }
+
ModMask mods_mask{};
ModMask mods_mods{};
VMod mods_vmods{};
@@ -574,6 +609,11 @@
};
struct KeySymMap {
+ bool operator==(const KeySymMap& other) const {
+ return kt_index == other.kt_index && groupInfo == other.groupInfo &&
+ width == other.width && syms == other.syms;
+ }
+
std::array<uint8_t, 4> kt_index{};
uint8_t groupInfo{};
uint8_t width{};
@@ -581,38 +621,70 @@
};
struct CommonBehavior {
+ bool operator==(const CommonBehavior& other) const {
+ return type == other.type && data == other.data;
+ }
+
uint8_t type{};
uint8_t data{};
};
struct DefaultBehavior {
+ bool operator==(const DefaultBehavior& other) const {
+ return type == other.type;
+ }
+
uint8_t type{};
};
struct LockBehavior {
+ bool operator==(const LockBehavior& other) const {
+ return type == other.type;
+ }
+
uint8_t type{};
};
struct RadioGroupBehavior {
+ bool operator==(const RadioGroupBehavior& other) const {
+ return type == other.type && group == other.group;
+ }
+
uint8_t type{};
uint8_t group{};
};
struct OverlayBehavior {
+ bool operator==(const OverlayBehavior& other) const {
+ return type == other.type && key == other.key;
+ }
+
uint8_t type{};
KeyCode key{};
};
struct PermamentLockBehavior {
+ bool operator==(const PermamentLockBehavior& other) const {
+ return type == other.type;
+ }
+
uint8_t type{};
};
struct PermamentRadioGroupBehavior {
+ bool operator==(const PermamentRadioGroupBehavior& other) const {
+ return type == other.type && group == other.group;
+ }
+
uint8_t type{};
uint8_t group{};
};
struct PermamentOverlayBehavior {
+ bool operator==(const PermamentOverlayBehavior& other) const {
+ return type == other.type && key == other.key;
+ }
+
uint8_t type{};
KeyCode key{};
};
@@ -640,27 +712,51 @@
};
struct SetExplicit {
+ bool operator==(const SetExplicit& other) const {
+ return keycode == other.keycode && c_explicit == other.c_explicit;
+ }
+
KeyCode keycode{};
Explicit c_explicit{};
};
struct KeyModMap {
+ bool operator==(const KeyModMap& other) const {
+ return keycode == other.keycode && mods == other.mods;
+ }
+
KeyCode keycode{};
ModMask mods{};
};
struct KeyVModMap {
+ bool operator==(const KeyVModMap& other) const {
+ return keycode == other.keycode && vmods == other.vmods;
+ }
+
KeyCode keycode{};
VMod vmods{};
};
struct KTSetMapEntry {
+ bool operator==(const KTSetMapEntry& other) const {
+ return level == other.level && realMods == other.realMods &&
+ virtualMods == other.virtualMods;
+ }
+
uint8_t level{};
ModMask realMods{};
VMod virtualMods{};
};
struct SetKeyType {
+ bool operator==(const SetKeyType& other) const {
+ return mask == other.mask && realMods == other.realMods &&
+ virtualMods == other.virtualMods && numLevels == other.numLevels &&
+ preserve == other.preserve && entries == other.entries &&
+ preserve_entries == other.preserve_entries;
+ }
+
ModMask mask{};
ModMask realMods{};
VMod virtualMods{};
@@ -671,11 +767,20 @@
};
struct Outline {
+ bool operator==(const Outline& other) const {
+ return cornerRadius == other.cornerRadius && points == other.points;
+ }
+
uint8_t cornerRadius{};
std::vector<Point> points{};
};
struct Shape {
+ bool operator==(const Shape& other) const {
+ return name == other.name && primaryNdx == other.primaryNdx &&
+ approxNdx == other.approxNdx && outlines == other.outlines;
+ }
+
Atom name{};
uint8_t primaryNdx{};
uint8_t approxNdx{};
@@ -683,6 +788,11 @@
};
struct Key {
+ bool operator==(const Key& other) const {
+ return name == other.name && gap == other.gap &&
+ shapeNdx == other.shapeNdx && colorNdx == other.colorNdx;
+ }
+
std::array<String8, 4> name{};
int16_t gap{};
uint8_t shapeNdx{};
@@ -690,21 +800,38 @@
};
struct OverlayKey {
+ bool operator==(const OverlayKey& other) const {
+ return over == other.over && under == other.under;
+ }
+
std::array<String8, 4> over{};
std::array<String8, 4> under{};
};
struct OverlayRow {
+ bool operator==(const OverlayRow& other) const {
+ return rowUnder == other.rowUnder && keys == other.keys;
+ }
+
uint8_t rowUnder{};
std::vector<OverlayKey> keys{};
};
struct Overlay {
+ bool operator==(const Overlay& other) const {
+ return name == other.name && rows == other.rows;
+ }
+
Atom name{};
std::vector<OverlayRow> rows{};
};
struct Row {
+ bool operator==(const Row& other) const {
+ return top == other.top && left == other.left &&
+ vertical == other.vertical && keys == other.keys;
+ }
+
int16_t top{};
int16_t left{};
uint8_t vertical{};
@@ -712,11 +839,23 @@
};
struct Listing {
+ bool operator==(const Listing& other) const {
+ return flags == other.flags && string == other.string;
+ }
+
uint16_t flags{};
std::vector<String8> string{};
};
struct DeviceLedInfo {
+ bool operator==(const DeviceLedInfo& other) const {
+ return ledClass == other.ledClass && ledID == other.ledID &&
+ namesPresent == other.namesPresent &&
+ mapsPresent == other.mapsPresent &&
+ physIndicators == other.physIndicators && state == other.state &&
+ names == other.names && maps == other.maps;
+ }
+
LedClass ledClass{};
IDSpec ledID{};
uint32_t namesPresent{};
@@ -737,10 +876,20 @@
};
struct SANoAction {
+ bool operator==(const SANoAction& other) const {
+ return type == other.type;
+ }
+
SAType type{};
};
struct SASetMods {
+ bool operator==(const SASetMods& other) const {
+ return type == other.type && flags == other.flags && mask == other.mask &&
+ realMods == other.realMods && vmodsHigh == other.vmodsHigh &&
+ vmodsLow == other.vmodsLow;
+ }
+
SAType type{};
Sa flags{};
ModMask mask{};
@@ -750,6 +899,12 @@
};
struct SALatchMods {
+ bool operator==(const SALatchMods& other) const {
+ return type == other.type && flags == other.flags && mask == other.mask &&
+ realMods == other.realMods && vmodsHigh == other.vmodsHigh &&
+ vmodsLow == other.vmodsLow;
+ }
+
SAType type{};
Sa flags{};
ModMask mask{};
@@ -759,6 +914,12 @@
};
struct SALockMods {
+ bool operator==(const SALockMods& other) const {
+ return type == other.type && flags == other.flags && mask == other.mask &&
+ realMods == other.realMods && vmodsHigh == other.vmodsHigh &&
+ vmodsLow == other.vmodsLow;
+ }
+
SAType type{};
Sa flags{};
ModMask mask{};
@@ -768,24 +929,42 @@
};
struct SASetGroup {
+ bool operator==(const SASetGroup& other) const {
+ return type == other.type && flags == other.flags && group == other.group;
+ }
+
SAType type{};
Sa flags{};
int8_t group{};
};
struct SALatchGroup {
+ bool operator==(const SALatchGroup& other) const {
+ return type == other.type && flags == other.flags && group == other.group;
+ }
+
SAType type{};
Sa flags{};
int8_t group{};
};
struct SALockGroup {
+ bool operator==(const SALockGroup& other) const {
+ return type == other.type && flags == other.flags && group == other.group;
+ }
+
SAType type{};
Sa flags{};
int8_t group{};
};
struct SAMovePtr {
+ bool operator==(const SAMovePtr& other) const {
+ return type == other.type && flags == other.flags &&
+ xHigh == other.xHigh && xLow == other.xLow &&
+ yHigh == other.yHigh && yLow == other.yLow;
+ }
+
SAType type{};
SAMovePtrFlag flags{};
int8_t xHigh{};
@@ -795,6 +974,11 @@
};
struct SAPtrBtn {
+ bool operator==(const SAPtrBtn& other) const {
+ return type == other.type && flags == other.flags &&
+ count == other.count && button == other.button;
+ }
+
SAType type{};
uint8_t flags{};
uint8_t count{};
@@ -802,12 +986,22 @@
};
struct SALockPtrBtn {
+ bool operator==(const SALockPtrBtn& other) const {
+ return type == other.type && flags == other.flags &&
+ button == other.button;
+ }
+
SAType type{};
uint8_t flags{};
uint8_t button{};
};
struct SASetPtrDflt {
+ bool operator==(const SASetPtrDflt& other) const {
+ return type == other.type && flags == other.flags &&
+ affect == other.affect && value == other.value;
+ }
+
SAType type{};
SASetPtrDfltFlag flags{};
SASetPtrDfltFlag affect{};
@@ -815,6 +1009,13 @@
};
struct SAIsoLock {
+ bool operator==(const SAIsoLock& other) const {
+ return type == other.type && flags == other.flags && mask == other.mask &&
+ realMods == other.realMods && group == other.group &&
+ affect == other.affect && vmodsHigh == other.vmodsHigh &&
+ vmodsLow == other.vmodsLow;
+ }
+
SAType type{};
SAIsoLockFlag flags{};
ModMask mask{};
@@ -826,34 +1027,66 @@
};
struct SATerminate {
+ bool operator==(const SATerminate& other) const {
+ return type == other.type;
+ }
+
SAType type{};
};
struct SASwitchScreen {
+ bool operator==(const SASwitchScreen& other) const {
+ return type == other.type && flags == other.flags &&
+ newScreen == other.newScreen;
+ }
+
SAType type{};
uint8_t flags{};
int8_t newScreen{};
};
struct SASetControls {
+ bool operator==(const SASetControls& other) const {
+ return type == other.type && boolCtrlsHigh == other.boolCtrlsHigh &&
+ boolCtrlsLow == other.boolCtrlsLow;
+ }
+
SAType type{};
BoolCtrlsHigh boolCtrlsHigh{};
BoolCtrlsLow boolCtrlsLow{};
};
struct SALockControls {
+ bool operator==(const SALockControls& other) const {
+ return type == other.type && boolCtrlsHigh == other.boolCtrlsHigh &&
+ boolCtrlsLow == other.boolCtrlsLow;
+ }
+
SAType type{};
BoolCtrlsHigh boolCtrlsHigh{};
BoolCtrlsLow boolCtrlsLow{};
};
struct SAActionMessage {
+ bool operator==(const SAActionMessage& other) const {
+ return type == other.type && flags == other.flags &&
+ message == other.message;
+ }
+
SAType type{};
ActionMessageFlag flags{};
std::array<uint8_t, 6> message{};
};
struct SARedirectKey {
+ bool operator==(const SARedirectKey& other) const {
+ return type == other.type && newkey == other.newkey &&
+ mask == other.mask && realModifiers == other.realModifiers &&
+ vmodsMaskHigh == other.vmodsMaskHigh &&
+ vmodsMaskLow == other.vmodsMaskLow &&
+ vmodsHigh == other.vmodsHigh && vmodsLow == other.vmodsLow;
+ }
+
SAType type{};
KeyCode newkey{};
ModMask mask{};
@@ -865,6 +1098,12 @@
};
struct SADeviceBtn {
+ bool operator==(const SADeviceBtn& other) const {
+ return type == other.type && flags == other.flags &&
+ count == other.count && button == other.button &&
+ device == other.device;
+ }
+
SAType type{};
uint8_t flags{};
uint8_t count{};
@@ -873,6 +1112,11 @@
};
struct SALockDeviceBtn {
+ bool operator==(const SALockDeviceBtn& other) const {
+ return type == other.type && flags == other.flags &&
+ button == other.button && device == other.device;
+ }
+
SAType type{};
LockDeviceFlags flags{};
uint8_t button{};
@@ -880,6 +1124,13 @@
};
struct SADeviceValuator {
+ bool operator==(const SADeviceValuator& other) const {
+ return type == other.type && device == other.device &&
+ val1what == other.val1what && val1index == other.val1index &&
+ val1value == other.val1value && val2what == other.val2what &&
+ val2index == other.val2index && val2value == other.val2value;
+ }
+
SAType type{};
uint8_t device{};
SAValWhat val1what{};
@@ -891,11 +1142,21 @@
};
struct SIAction {
+ bool operator==(const SIAction& other) const {
+ return type == other.type && data == other.data;
+ }
+
SAType type{};
std::array<uint8_t, 7> data{};
};
struct SymInterpret {
+ bool operator==(const SymInterpret& other) const {
+ return sym == other.sym && mods == other.mods && match == other.match &&
+ virtualMod == other.virtualMod && flags == other.flags &&
+ action == other.action;
+ }
+
KeySym sym{};
ModMask mods{};
uint8_t match{};
@@ -933,9 +1194,8 @@
static_assert(std::is_trivially_copyable<Action>::value, "");
struct NewKeyboardNotifyEvent {
- static constexpr int type_id = 38;
+ static constexpr int type_id = 40;
static constexpr uint8_t opcode = 0;
- bool send_event{};
uint8_t xkbType{};
uint16_t sequence{};
Time time{};
@@ -953,9 +1213,8 @@
};
struct MapNotifyEvent {
- static constexpr int type_id = 39;
+ static constexpr int type_id = 41;
static constexpr uint8_t opcode = 1;
- bool send_event{};
uint8_t xkbType{};
uint16_t sequence{};
Time time{};
@@ -984,9 +1243,8 @@
};
struct StateNotifyEvent {
- static constexpr int type_id = 40;
+ static constexpr int type_id = 42;
static constexpr uint8_t opcode = 2;
- bool send_event{};
uint8_t xkbType{};
uint16_t sequence{};
Time time{};
@@ -1015,9 +1273,8 @@
};
struct ControlsNotifyEvent {
- static constexpr int type_id = 41;
+ static constexpr int type_id = 43;
static constexpr uint8_t opcode = 3;
- bool send_event{};
uint8_t xkbType{};
uint16_t sequence{};
Time time{};
@@ -1035,9 +1292,8 @@
};
struct IndicatorStateNotifyEvent {
- static constexpr int type_id = 42;
+ static constexpr int type_id = 44;
static constexpr uint8_t opcode = 4;
- bool send_event{};
uint8_t xkbType{};
uint16_t sequence{};
Time time{};
@@ -1049,9 +1305,8 @@
};
struct IndicatorMapNotifyEvent {
- static constexpr int type_id = 43;
+ static constexpr int type_id = 45;
static constexpr uint8_t opcode = 5;
- bool send_event{};
uint8_t xkbType{};
uint16_t sequence{};
Time time{};
@@ -1063,9 +1318,8 @@
};
struct NamesNotifyEvent {
- static constexpr int type_id = 44;
+ static constexpr int type_id = 46;
static constexpr uint8_t opcode = 6;
- bool send_event{};
uint8_t xkbType{};
uint16_t sequence{};
Time time{};
@@ -1087,9 +1341,8 @@
};
struct CompatMapNotifyEvent {
- static constexpr int type_id = 45;
+ static constexpr int type_id = 47;
static constexpr uint8_t opcode = 7;
- bool send_event{};
uint8_t xkbType{};
uint16_t sequence{};
Time time{};
@@ -1103,9 +1356,8 @@
};
struct BellNotifyEvent {
- static constexpr int type_id = 46;
+ static constexpr int type_id = 48;
static constexpr uint8_t opcode = 8;
- bool send_event{};
uint8_t xkbType{};
uint16_t sequence{};
Time time{};
@@ -1123,9 +1375,8 @@
};
struct ActionMessageEvent {
- static constexpr int type_id = 47;
+ static constexpr int type_id = 49;
static constexpr uint8_t opcode = 9;
- bool send_event{};
uint8_t xkbType{};
uint16_t sequence{};
Time time{};
@@ -1141,9 +1392,8 @@
};
struct AccessXNotifyEvent {
- static constexpr int type_id = 48;
+ static constexpr int type_id = 50;
static constexpr uint8_t opcode = 10;
- bool send_event{};
uint8_t xkbType{};
uint16_t sequence{};
Time time{};
@@ -1157,9 +1407,8 @@
};
struct ExtensionDeviceNotifyEvent {
- static constexpr int type_id = 49;
+ static constexpr int type_id = 51;
static constexpr uint8_t opcode = 11;
- bool send_event{};
uint8_t xkbType{};
uint16_t sequence{};
Time time{};
diff --git a/ui/gfx/x/generated_protos/xprint.cc b/ui/gfx/x/generated_protos/xprint.cc
index e6d6d84..e66a2ed 100644
--- a/ui/gfx/x/generated_protos/xprint.cc
+++ b/ui/gfx/x/generated_protos/xprint.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "xprint.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
@@ -111,7 +112,10 @@
std::string XPrint::BadContextError::ToString() const {
std::stringstream ss_;
ss_ << "XPrint::BadContextError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -122,6 +126,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -134,12 +141,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string XPrint::BadSequenceError::ToString() const {
std::stringstream ss_;
ss_ << "XPrint::BadSequenceError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -150,6 +169,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -162,6 +184,15 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
Future<XPrint::PrintQueryVersionReply> XPrint::PrintQueryVersion(
@@ -271,6 +302,9 @@
buf.Write(&printer_name_elem);
}
+ // pad0
+ Align(&buf, 4);
+
// locale
DCHECK_EQ(static_cast<size_t>(localeLen), locale.size());
for (auto& locale_elem : locale) {
@@ -444,6 +478,9 @@
buf.Write(&printerName_elem);
}
+ // pad0
+ Align(&buf, 4);
+
// locale
DCHECK_EQ(static_cast<size_t>(localeLen), locale.size());
for (auto& locale_elem : locale) {
@@ -838,6 +875,9 @@
buf.Write(&data_elem);
}
+ // pad0
+ Align(&buf, 4);
+
// doc_format
DCHECK_EQ(static_cast<size_t>(len_fmt), doc_format.size());
for (auto& doc_format_elem : doc_format) {
@@ -845,6 +885,9 @@
buf.Write(&doc_format_elem);
}
+ // pad1
+ Align(&buf, 4);
+
// options
DCHECK_EQ(static_cast<size_t>(len_options), options.size());
for (auto& options_elem : options) {
diff --git a/ui/gfx/x/generated_protos/xprint.h b/ui/gfx/x/generated_protos/xprint.h
index 0b776ae..5ba5ed2 100644
--- a/ui/gfx/x/generated_protos/xprint.h
+++ b/ui/gfx/x/generated_protos/xprint.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -115,14 +115,17 @@
};
struct Printer {
+ bool operator==(const Printer& other) const {
+ return name == other.name && description == other.description;
+ }
+
std::vector<String8> name{};
std::vector<String8> description{};
};
struct NotifyEvent {
- static constexpr int type_id = 50;
+ static constexpr int type_id = 52;
static constexpr uint8_t opcode = 0;
- bool send_event{};
uint8_t detail{};
uint16_t sequence{};
PContext context{};
@@ -132,9 +135,8 @@
};
struct AttributNotifyEvent {
- static constexpr int type_id = 51;
+ static constexpr int type_id = 53;
static constexpr uint8_t opcode = 1;
- bool send_event{};
uint8_t detail{};
uint16_t sequence{};
PContext context{};
@@ -144,12 +146,18 @@
struct BadContextError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct BadSequenceError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
diff --git a/ui/gfx/x/generated_protos/xproto.cc b/ui/gfx/x/generated_protos/xproto.cc
index 0d8e008..25e6338 100644
--- a/ui/gfx/x/generated_protos/xproto.cc
+++ b/ui/gfx/x/generated_protos/xproto.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "xproto.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/xproto.h b/ui/gfx/x/generated_protos/xproto.h
index fef9551..be5004e 100644
--- a/ui/gfx/x/generated_protos/xproto.h
+++ b/ui/gfx/x/generated_protos/xproto.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -695,16 +695,29 @@
};
struct Char16 {
+ bool operator==(const Char16& other) const {
+ return byte1 == other.byte1 && byte2 == other.byte2;
+ }
+
uint8_t byte1{};
uint8_t byte2{};
};
struct Point {
+ bool operator==(const Point& other) const {
+ return x == other.x && y == other.y;
+ }
+
int16_t x{};
int16_t y{};
};
struct Rectangle {
+ bool operator==(const Rectangle& other) const {
+ return x == other.x && y == other.y && width == other.width &&
+ height == other.height;
+ }
+
int16_t x{};
int16_t y{};
uint16_t width{};
@@ -712,6 +725,12 @@
};
struct Arc {
+ bool operator==(const Arc& other) const {
+ return x == other.x && y == other.y && width == other.width &&
+ height == other.height && angle1 == other.angle1 &&
+ angle2 == other.angle2;
+ }
+
int16_t x{};
int16_t y{};
uint16_t width{};
@@ -721,12 +740,25 @@
};
struct Format {
+ bool operator==(const Format& other) const {
+ return depth == other.depth && bits_per_pixel == other.bits_per_pixel &&
+ scanline_pad == other.scanline_pad;
+ }
+
uint8_t depth{};
uint8_t bits_per_pixel{};
uint8_t scanline_pad{};
};
struct VisualType {
+ bool operator==(const VisualType& other) const {
+ return visual_id == other.visual_id && c_class == other.c_class &&
+ bits_per_rgb_value == other.bits_per_rgb_value &&
+ colormap_entries == other.colormap_entries &&
+ red_mask == other.red_mask && green_mask == other.green_mask &&
+ blue_mask == other.blue_mask;
+ }
+
VisualId visual_id{};
VisualClass c_class{};
uint8_t bits_per_rgb_value{};
@@ -737,11 +769,32 @@
};
struct Depth {
+ bool operator==(const Depth& other) const {
+ return depth == other.depth && visuals == other.visuals;
+ }
+
uint8_t depth{};
std::vector<VisualType> visuals{};
};
struct Screen {
+ bool operator==(const Screen& other) const {
+ return root == other.root && default_colormap == other.default_colormap &&
+ white_pixel == other.white_pixel &&
+ black_pixel == other.black_pixel &&
+ current_input_masks == other.current_input_masks &&
+ width_in_pixels == other.width_in_pixels &&
+ height_in_pixels == other.height_in_pixels &&
+ width_in_millimeters == other.width_in_millimeters &&
+ height_in_millimeters == other.height_in_millimeters &&
+ min_installed_maps == other.min_installed_maps &&
+ max_installed_maps == other.max_installed_maps &&
+ root_visual == other.root_visual &&
+ backing_stores == other.backing_stores &&
+ save_unders == other.save_unders && root_depth == other.root_depth &&
+ allowed_depths == other.allowed_depths;
+ }
+
Window root{};
ColorMap default_colormap{};
uint32_t white_pixel{};
@@ -761,6 +814,14 @@
};
struct SetupRequest {
+ bool operator==(const SetupRequest& other) const {
+ return byte_order == other.byte_order &&
+ protocol_major_version == other.protocol_major_version &&
+ protocol_minor_version == other.protocol_minor_version &&
+ authorization_protocol_name == other.authorization_protocol_name &&
+ authorization_protocol_data == other.authorization_protocol_data;
+ }
+
uint8_t byte_order{};
uint16_t protocol_major_version{};
uint16_t protocol_minor_version{};
@@ -769,6 +830,13 @@
};
struct SetupFailed {
+ bool operator==(const SetupFailed& other) const {
+ return status == other.status &&
+ protocol_major_version == other.protocol_major_version &&
+ protocol_minor_version == other.protocol_minor_version &&
+ length == other.length && reason == other.reason;
+ }
+
uint8_t status{};
uint16_t protocol_major_version{};
uint16_t protocol_minor_version{};
@@ -777,12 +845,35 @@
};
struct SetupAuthenticate {
+ bool operator==(const SetupAuthenticate& other) const {
+ return status == other.status && length == other.length &&
+ reason == other.reason;
+ }
+
uint8_t status{};
uint16_t length{};
std::string reason{};
};
struct Setup {
+ bool operator==(const Setup& other) const {
+ return status == other.status &&
+ protocol_major_version == other.protocol_major_version &&
+ protocol_minor_version == other.protocol_minor_version &&
+ length == other.length && release_number == other.release_number &&
+ resource_id_base == other.resource_id_base &&
+ resource_id_mask == other.resource_id_mask &&
+ motion_buffer_size == other.motion_buffer_size &&
+ maximum_request_length == other.maximum_request_length &&
+ image_byte_order == other.image_byte_order &&
+ bitmap_format_bit_order == other.bitmap_format_bit_order &&
+ bitmap_format_scanline_unit == other.bitmap_format_scanline_unit &&
+ bitmap_format_scanline_pad == other.bitmap_format_scanline_pad &&
+ min_keycode == other.min_keycode &&
+ max_keycode == other.max_keycode && vendor == other.vendor &&
+ pixmap_formats == other.pixmap_formats && roots == other.roots;
+ }
+
uint8_t status{};
uint16_t protocol_major_version{};
uint16_t protocol_minor_version{};
@@ -804,12 +895,11 @@
};
struct KeyEvent {
- static constexpr int type_id = 52;
+ static constexpr int type_id = 54;
enum Opcode {
Press = 2,
Release = 3,
} opcode{};
- bool send_event{};
KeyCode detail{};
uint16_t sequence{};
Time time{};
@@ -827,12 +917,11 @@
};
struct ButtonEvent {
- static constexpr int type_id = 53;
+ static constexpr int type_id = 55;
enum Opcode {
Press = 4,
Release = 5,
} opcode{};
- bool send_event{};
Button detail{};
uint16_t sequence{};
Time time{};
@@ -850,9 +939,8 @@
};
struct MotionNotifyEvent {
- static constexpr int type_id = 54;
+ static constexpr int type_id = 56;
static constexpr uint8_t opcode = 6;
- bool send_event{};
Motion detail{};
uint16_t sequence{};
Time time{};
@@ -870,12 +958,11 @@
};
struct CrossingEvent {
- static constexpr int type_id = 55;
+ static constexpr int type_id = 57;
enum Opcode {
EnterNotify = 7,
LeaveNotify = 8,
} opcode{};
- bool send_event{};
NotifyDetail detail{};
uint16_t sequence{};
Time time{};
@@ -894,12 +981,11 @@
};
struct FocusEvent {
- static constexpr int type_id = 56;
+ static constexpr int type_id = 58;
enum Opcode {
In = 9,
Out = 10,
} opcode{};
- bool send_event{};
NotifyDetail detail{};
uint16_t sequence{};
Window event{};
@@ -909,18 +995,16 @@
};
struct KeymapNotifyEvent {
- static constexpr int type_id = 57;
+ static constexpr int type_id = 59;
static constexpr uint8_t opcode = 11;
- bool send_event{};
std::array<uint8_t, 31> keys{};
x11::Window* GetWindow() { return nullptr; }
};
struct ExposeEvent {
- static constexpr int type_id = 58;
+ static constexpr int type_id = 60;
static constexpr uint8_t opcode = 12;
- bool send_event{};
uint16_t sequence{};
Window window{};
uint16_t x{};
@@ -933,9 +1017,8 @@
};
struct GraphicsExposureEvent {
- static constexpr int type_id = 59;
+ static constexpr int type_id = 61;
static constexpr uint8_t opcode = 13;
- bool send_event{};
uint16_t sequence{};
Drawable drawable{};
uint16_t x{};
@@ -950,9 +1033,8 @@
};
struct NoExposureEvent {
- static constexpr int type_id = 60;
+ static constexpr int type_id = 62;
static constexpr uint8_t opcode = 14;
- bool send_event{};
uint16_t sequence{};
Drawable drawable{};
uint16_t minor_opcode{};
@@ -962,9 +1044,8 @@
};
struct VisibilityNotifyEvent {
- static constexpr int type_id = 61;
+ static constexpr int type_id = 63;
static constexpr uint8_t opcode = 15;
- bool send_event{};
uint16_t sequence{};
Window window{};
Visibility state{};
@@ -973,9 +1054,8 @@
};
struct CreateNotifyEvent {
- static constexpr int type_id = 62;
+ static constexpr int type_id = 64;
static constexpr uint8_t opcode = 16;
- bool send_event{};
uint16_t sequence{};
Window parent{};
Window window{};
@@ -990,44 +1070,40 @@
};
struct DestroyNotifyEvent {
- static constexpr int type_id = 63;
+ static constexpr int type_id = 65;
static constexpr uint8_t opcode = 17;
- bool send_event{};
uint16_t sequence{};
Window event{};
Window window{};
- x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
};
struct UnmapNotifyEvent {
- static constexpr int type_id = 64;
+ static constexpr int type_id = 66;
static constexpr uint8_t opcode = 18;
- bool send_event{};
uint16_t sequence{};
Window event{};
Window window{};
uint8_t from_configure{};
- x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
};
struct MapNotifyEvent {
- static constexpr int type_id = 65;
+ static constexpr int type_id = 67;
static constexpr uint8_t opcode = 19;
- bool send_event{};
uint16_t sequence{};
Window event{};
Window window{};
uint8_t override_redirect{};
- x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
};
struct MapRequestEvent {
- static constexpr int type_id = 66;
+ static constexpr int type_id = 68;
static constexpr uint8_t opcode = 20;
- bool send_event{};
uint16_t sequence{};
Window parent{};
Window window{};
@@ -1036,9 +1112,8 @@
};
struct ReparentNotifyEvent {
- static constexpr int type_id = 67;
+ static constexpr int type_id = 69;
static constexpr uint8_t opcode = 21;
- bool send_event{};
uint16_t sequence{};
Window event{};
Window window{};
@@ -1047,13 +1122,12 @@
int16_t y{};
uint8_t override_redirect{};
- x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
};
struct ConfigureNotifyEvent {
- static constexpr int type_id = 68;
+ static constexpr int type_id = 70;
static constexpr uint8_t opcode = 22;
- bool send_event{};
uint16_t sequence{};
Window event{};
Window window{};
@@ -1065,13 +1139,12 @@
uint16_t border_width{};
uint8_t override_redirect{};
- x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
};
struct ConfigureRequestEvent {
- static constexpr int type_id = 69;
+ static constexpr int type_id = 71;
static constexpr uint8_t opcode = 23;
- bool send_event{};
StackMode stack_mode{};
uint16_t sequence{};
Window parent{};
@@ -1088,22 +1161,20 @@
};
struct GravityNotifyEvent {
- static constexpr int type_id = 70;
+ static constexpr int type_id = 72;
static constexpr uint8_t opcode = 24;
- bool send_event{};
uint16_t sequence{};
Window event{};
Window window{};
int16_t x{};
int16_t y{};
- x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
};
struct ResizeRequestEvent {
- static constexpr int type_id = 71;
+ static constexpr int type_id = 73;
static constexpr uint8_t opcode = 25;
- bool send_event{};
uint16_t sequence{};
Window window{};
uint16_t width{};
@@ -1113,24 +1184,22 @@
};
struct CirculateEvent {
- static constexpr int type_id = 72;
+ static constexpr int type_id = 74;
enum Opcode {
Notify = 26,
Request = 27,
} opcode{};
- bool send_event{};
uint16_t sequence{};
Window event{};
Window window{};
Place place{};
- x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&event); }
+ x11::Window* GetWindow() { return reinterpret_cast<x11::Window*>(&window); }
};
struct PropertyNotifyEvent {
- static constexpr int type_id = 73;
+ static constexpr int type_id = 75;
static constexpr uint8_t opcode = 28;
- bool send_event{};
uint16_t sequence{};
Window window{};
Atom atom{};
@@ -1141,9 +1210,8 @@
};
struct SelectionClearEvent {
- static constexpr int type_id = 74;
+ static constexpr int type_id = 76;
static constexpr uint8_t opcode = 29;
- bool send_event{};
uint16_t sequence{};
Time time{};
Window owner{};
@@ -1153,9 +1221,8 @@
};
struct SelectionRequestEvent {
- static constexpr int type_id = 75;
+ static constexpr int type_id = 77;
static constexpr uint8_t opcode = 30;
- bool send_event{};
uint16_t sequence{};
Time time{};
Window owner{};
@@ -1168,9 +1235,8 @@
};
struct SelectionNotifyEvent {
- static constexpr int type_id = 76;
+ static constexpr int type_id = 78;
static constexpr uint8_t opcode = 31;
- bool send_event{};
uint16_t sequence{};
Time time{};
Window requestor{};
@@ -1184,9 +1250,8 @@
};
struct ColormapNotifyEvent {
- static constexpr int type_id = 77;
+ static constexpr int type_id = 79;
static constexpr uint8_t opcode = 32;
- bool send_event{};
uint16_t sequence{};
Window window{};
ColorMap colormap{};
@@ -1206,9 +1271,8 @@
static_assert(std::is_trivially_copyable<ClientMessageData>::value, "");
struct ClientMessageEvent {
- static constexpr int type_id = 78;
+ static constexpr int type_id = 80;
static constexpr uint8_t opcode = 33;
- bool send_event{};
uint8_t format{};
uint16_t sequence{};
Window window{};
@@ -1219,9 +1283,8 @@
};
struct MappingNotifyEvent {
- static constexpr int type_id = 79;
+ static constexpr int type_id = 81;
static constexpr uint8_t opcode = 34;
- bool send_event{};
uint16_t sequence{};
Mapping request{};
KeyCode first_keycode{};
@@ -1231,9 +1294,8 @@
};
struct GeGenericEvent {
- static constexpr int type_id = 80;
+ static constexpr int type_id = 82;
static constexpr uint8_t opcode = 35;
- bool send_event{};
uint16_t sequence{};
x11::Window* GetWindow() { return nullptr; }
@@ -1393,17 +1455,32 @@
};
struct TimeCoord {
+ bool operator==(const TimeCoord& other) const {
+ return time == other.time && x == other.x && y == other.y;
+ }
+
Time time{};
int16_t x{};
int16_t y{};
};
struct FontProperty {
+ bool operator==(const FontProperty& other) const {
+ return name == other.name && value == other.value;
+ }
+
Atom name{};
uint32_t value{};
};
struct CharInfo {
+ bool operator==(const CharInfo& other) const {
+ return left_side_bearing == other.left_side_bearing &&
+ right_side_bearing == other.right_side_bearing &&
+ character_width == other.character_width && ascent == other.ascent &&
+ descent == other.descent && attributes == other.attributes;
+ }
+
int16_t left_side_bearing{};
int16_t right_side_bearing{};
int16_t character_width{};
@@ -1413,10 +1490,16 @@
};
struct Str {
+ bool operator==(const Str& other) const { return name == other.name; }
+
std::string name{};
};
struct Segment {
+ bool operator==(const Segment& other) const {
+ return x1 == other.x1 && y1 == other.y1 && x2 == other.x2 && y2 == other.y2;
+ }
+
int16_t x1{};
int16_t y1{};
int16_t x2{};
@@ -1424,6 +1507,11 @@
};
struct ColorItem {
+ bool operator==(const ColorItem& other) const {
+ return pixel == other.pixel && red == other.red && green == other.green &&
+ blue == other.blue && flags == other.flags;
+ }
+
uint32_t pixel{};
uint16_t red{};
uint16_t green{};
@@ -1432,12 +1520,20 @@
};
struct Rgb {
+ bool operator==(const Rgb& other) const {
+ return red == other.red && green == other.green && blue == other.blue;
+ }
+
uint16_t red{};
uint16_t green{};
uint16_t blue{};
};
struct Host {
+ bool operator==(const Host& other) const {
+ return family == other.family && address == other.address;
+ }
+
Family family{};
std::vector<uint8_t> address{};
};
diff --git a/ui/gfx/x/generated_protos/xselinux.cc b/ui/gfx/x/generated_protos/xselinux.cc
index 453b3de..42eea9d 100644
--- a/ui/gfx/x/generated_protos/xselinux.cc
+++ b/ui/gfx/x/generated_protos/xselinux.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "xselinux.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/xselinux.h b/ui/gfx/x/generated_protos/xselinux.h
index 172395a..3ed18e6 100644
--- a/ui/gfx/x/generated_protos/xselinux.h
+++ b/ui/gfx/x/generated_protos/xselinux.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -81,6 +81,11 @@
Connection* connection() const { return connection_; }
struct ListItem {
+ bool operator==(const ListItem& other) const {
+ return name == other.name && object_context == other.object_context &&
+ data_context == other.data_context;
+ }
+
Atom name{};
std::string object_context{};
std::string data_context{};
diff --git a/ui/gfx/x/generated_protos/xtest.cc b/ui/gfx/x/generated_protos/xtest.cc
index 709caef..1e7ce07 100644
--- a/ui/gfx/x/generated_protos/xtest.cc
+++ b/ui/gfx/x/generated_protos/xtest.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "xtest.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/xtest.h b/ui/gfx/x/generated_protos/xtest.h
index b987f53..00f697f 100644
--- a/ui/gfx/x/generated_protos/xtest.h
+++ b/ui/gfx/x/generated_protos/xtest.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/generated_protos/xv.cc b/ui/gfx/x/generated_protos/xv.cc
index 0171ced..5a28c40 100644
--- a/ui/gfx/x/generated_protos/xv.cc
+++ b/ui/gfx/x/generated_protos/xv.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "xv.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
@@ -55,7 +56,10 @@
std::string Xv::BadPortError::ToString() const {
std::stringstream ss_;
ss_ << "Xv::BadPortError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -65,6 +69,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -77,12 +84,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string Xv::BadEncodingError::ToString() const {
std::stringstream ss_;
ss_ << "Xv::BadEncodingError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -93,6 +112,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -105,12 +127,24 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
std::string Xv::BadControlError::ToString() const {
std::stringstream ss_;
ss_ << "Xv::BadControlError{";
- ss_ << ".sequence = " << static_cast<uint64_t>(sequence);
+ ss_ << ".sequence = " << static_cast<uint64_t>(sequence) << ", ";
+ ss_ << ".bad_value = " << static_cast<uint64_t>(bad_value) << ", ";
+ ss_ << ".minor_opcode = " << static_cast<uint64_t>(minor_opcode) << ", ";
+ ss_ << ".major_opcode = " << static_cast<uint64_t>(major_opcode);
ss_ << "}";
return ss_.str();
}
@@ -121,6 +155,9 @@
auto& buf = *buffer;
auto& sequence = (*error_).sequence;
+ auto& bad_value = (*error_).bad_value;
+ auto& minor_opcode = (*error_).minor_opcode;
+ auto& major_opcode = (*error_).major_opcode;
// response_type
uint8_t response_type;
@@ -133,6 +170,15 @@
// sequence
Read(&sequence, &buf);
+ // bad_value
+ Read(&bad_value, &buf);
+
+ // minor_opcode
+ Read(&minor_opcode, &buf);
+
+ // major_opcode
+ Read(&major_opcode, &buf);
+
DCHECK_LE(buf.offset, 32ul);
}
template <>
diff --git a/ui/gfx/x/generated_protos/xv.h b/ui/gfx/x/generated_protos/xv.h
index c4a89f3..652e85b 100644
--- a/ui/gfx/x/generated_protos/xv.h
+++ b/ui/gfx/x/generated_protos/xv.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -131,16 +131,30 @@
};
struct Rational {
+ bool operator==(const Rational& other) const {
+ return numerator == other.numerator && denominator == other.denominator;
+ }
+
int32_t numerator{};
int32_t denominator{};
};
struct Format {
+ bool operator==(const Format& other) const {
+ return visual == other.visual && depth == other.depth;
+ }
+
VisualId visual{};
uint8_t depth{};
};
struct AdaptorInfo {
+ bool operator==(const AdaptorInfo& other) const {
+ return base_id == other.base_id && num_ports == other.num_ports &&
+ type == other.type && name == other.name &&
+ formats == other.formats;
+ }
+
Port base_id{};
uint16_t num_ports{};
Type type{};
@@ -149,6 +163,11 @@
};
struct EncodingInfo {
+ bool operator==(const EncodingInfo& other) const {
+ return encoding == other.encoding && width == other.width &&
+ height == other.height && rate == other.rate && name == other.name;
+ }
+
Encoding encoding{};
uint16_t width{};
uint16_t height{};
@@ -157,6 +176,12 @@
};
struct Image {
+ bool operator==(const Image& other) const {
+ return id == other.id && width == other.width && height == other.height &&
+ pitches == other.pitches && offsets == other.offsets &&
+ data == other.data;
+ }
+
uint32_t id{};
uint16_t width{};
uint16_t height{};
@@ -166,6 +191,11 @@
};
struct AttributeInfo {
+ bool operator==(const AttributeInfo& other) const {
+ return flags == other.flags && min == other.min && max == other.max &&
+ name == other.name;
+ }
+
AttributeFlag flags{};
int32_t min{};
int32_t max{};
@@ -173,6 +203,25 @@
};
struct ImageFormatInfo {
+ bool operator==(const ImageFormatInfo& other) const {
+ return id == other.id && type == other.type &&
+ byte_order == other.byte_order && guid == other.guid &&
+ bpp == other.bpp && num_planes == other.num_planes &&
+ depth == other.depth && red_mask == other.red_mask &&
+ green_mask == other.green_mask && blue_mask == other.blue_mask &&
+ format == other.format && y_sample_bits == other.y_sample_bits &&
+ u_sample_bits == other.u_sample_bits &&
+ v_sample_bits == other.v_sample_bits &&
+ vhorz_y_period == other.vhorz_y_period &&
+ vhorz_u_period == other.vhorz_u_period &&
+ vhorz_v_period == other.vhorz_v_period &&
+ vvert_y_period == other.vvert_y_period &&
+ vvert_u_period == other.vvert_u_period &&
+ vvert_v_period == other.vvert_v_period &&
+ vcomp_order == other.vcomp_order &&
+ vscanline_order == other.vscanline_order;
+ }
+
uint32_t id{};
ImageFormatInfoType type{};
ImageOrder byte_order{};
@@ -199,26 +248,34 @@
struct BadPortError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct BadEncodingError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct BadControlError : public x11::Error {
uint16_t sequence{};
+ uint32_t bad_value{};
+ uint16_t minor_opcode{};
+ uint8_t major_opcode{};
std::string ToString() const override;
};
struct VideoNotifyEvent {
- static constexpr int type_id = 81;
+ static constexpr int type_id = 83;
static constexpr uint8_t opcode = 0;
- bool send_event{};
VideoNotifyReason reason{};
uint16_t sequence{};
Time time{};
@@ -231,9 +288,8 @@
};
struct PortNotifyEvent {
- static constexpr int type_id = 82;
+ static constexpr int type_id = 84;
static constexpr uint8_t opcode = 1;
- bool send_event{};
uint16_t sequence{};
Time time{};
Port port{};
diff --git a/ui/gfx/x/generated_protos/xvmc.cc b/ui/gfx/x/generated_protos/xvmc.cc
index 98fbbb5..4fa70ec 100644
--- a/ui/gfx/x/generated_protos/xvmc.cc
+++ b/ui/gfx/x/generated_protos/xvmc.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -40,6 +40,7 @@
#include "xvmc.h"
+#include <unistd.h>
#include <xcb/xcb.h>
#include <xcb/xcbext.h>
diff --git a/ui/gfx/x/generated_protos/xvmc.h b/ui/gfx/x/generated_protos/xvmc.h
index b166167..38ca9fa 100644
--- a/ui/gfx/x/generated_protos/xvmc.h
+++ b/ui/gfx/x/generated_protos/xvmc.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -88,6 +88,15 @@
enum class SubPicture : uint32_t {};
struct SurfaceInfo {
+ bool operator==(const SurfaceInfo& other) const {
+ return id == other.id && chroma_format == other.chroma_format &&
+ pad0 == other.pad0 && max_width == other.max_width &&
+ max_height == other.max_height &&
+ subpicture_max_width == other.subpicture_max_width &&
+ subpicture_max_height == other.subpicture_max_height &&
+ mc_type == other.mc_type && flags == other.flags;
+ }
+
Surface id{};
uint16_t chroma_format{};
uint16_t pad0{};
diff --git a/ui/gfx/x/keyboard_state.cc b/ui/gfx/x/keyboard_state.cc
index 147b6c0..d177d09 100644
--- a/ui/gfx/x/keyboard_state.cc
+++ b/ui/gfx/x/keyboard_state.cc
@@ -1,10 +1,11 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/gfx/x/keyboard_state.h"
#include "base/i18n/case_conversion.h"
+#include "base/memory/raw_ptr.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/future.h"
#include "ui/gfx/x/keysyms/keysyms.h"
@@ -84,7 +85,7 @@
&mode_switch_, &num_lock_);
}
- Connection* const connection_;
+ const raw_ptr<Connection> connection_;
GetKeyboardMappingReply keyboard_mapping_;
uint16_t lock_meaning_ = 0;
uint8_t mode_switch_ = 0;
@@ -124,7 +125,7 @@
map_ = std::move(*response.reply);
}
- Connection* const connection_;
+ const raw_ptr<Connection> connection_;
Xkb::GetMapReply map_;
};
diff --git a/ui/gfx/x/keyboard_state.h b/ui/gfx/x/keyboard_state.h
index d28fe59..8bd0473 100644
--- a/ui/gfx/x/keyboard_state.h
+++ b/ui/gfx/x/keyboard_state.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/keysyms/BUILD.gn b/ui/gfx/x/keysyms/BUILD.gn
index 7ebb583..e3ac347 100644
--- a/ui/gfx/x/keysyms/BUILD.gn
+++ b/ui/gfx/x/keysyms/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2020 The Chromium Authors. All rights reserved.
+# Copyright 2020 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/ui/gfx/x/keysyms/keysyms.h b/ui/gfx/x/keysyms/keysyms.h
index c43ca1a..7d3648c 100644
--- a/ui/gfx/x/keysyms/keysyms.h
+++ b/ui/gfx/x/keysyms/keysyms.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/property_cache.cc b/ui/gfx/x/property_cache.cc
index 2f318a2..550fe15 100644
--- a/ui/gfx/x/property_cache.cc
+++ b/ui/gfx/x/property_cache.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -37,7 +37,7 @@
DCHECK(it != properties_.end());
if (!it->second.response.has_value())
- it->second.future.Wait();
+ it->second.future.DispatchNow();
DCHECK(it->second.response.has_value());
return it->second.response.value();
diff --git a/ui/gfx/x/property_cache.h b/ui/gfx/x/property_cache.h
index 1004b07..d617a51 100644
--- a/ui/gfx/x/property_cache.h
+++ b/ui/gfx/x/property_cache.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,6 +9,7 @@
#include "base/component_export.h"
#include "base/containers/flat_map.h"
+#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/weak_ptr.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
@@ -72,7 +73,7 @@
void OnGetPropertyResponse(PropertyValue* value,
GetPropertyResponse response);
- Connection* connection_;
+ raw_ptr<Connection> connection_;
Window window_;
XScopedEventSelector event_selector_;
base::flat_map<Atom, PropertyValue> properties_;
diff --git a/ui/gfx/x/property_cache_unittest.cc b/ui/gfx/x/property_cache_unittest.cc
index ffc39d6..bf801fe 100644
--- a/ui/gfx/x/property_cache_unittest.cc
+++ b/ui/gfx/x/property_cache_unittest.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,7 @@
#include <memory>
+#include "base/memory/raw_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/x/x11_atom_cache.h"
#include "ui/gfx/x/xproto.h"
@@ -39,7 +40,7 @@
connection_ = nullptr;
}
- Connection* connection_ = nullptr;
+ raw_ptr<Connection> connection_ = nullptr;
Window window_ = Window::None;
};
diff --git a/ui/gfx/x/ref_counted_fd.cc b/ui/gfx/x/ref_counted_fd.cc
index 64ed2a8..151ecac 100644
--- a/ui/gfx/x/ref_counted_fd.cc
+++ b/ui/gfx/x/ref_counted_fd.cc
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/ref_counted_fd.h b/ui/gfx/x/ref_counted_fd.h
index 991c9e7..95a97ef 100644
--- a/ui/gfx/x/ref_counted_fd.h
+++ b/ui/gfx/x/ref_counted_fd.h
@@ -1,4 +1,4 @@
-// Copyright 2021 The Chromium Authors. All rights reserved.
+// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/scoped_ignore_errors.cc b/ui/gfx/x/scoped_ignore_errors.cc
index 9364dbd..61448e4 100644
--- a/ui/gfx/x/scoped_ignore_errors.cc
+++ b/ui/gfx/x/scoped_ignore_errors.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/scoped_ignore_errors.h b/ui/gfx/x/scoped_ignore_errors.h
index baa48b5..a5e877d 100644
--- a/ui/gfx/x/scoped_ignore_errors.h
+++ b/ui/gfx/x/scoped_ignore_errors.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -6,6 +6,7 @@
#define UI_GFX_X_SCOPED_IGNORE_ERRORS_H_
#include "base/component_export.h"
+#include "base/memory/raw_ptr.h"
#include "ui/gfx/x/connection.h"
namespace x11 {
@@ -17,7 +18,7 @@
~ScopedIgnoreErrors();
private:
- Connection* const connection_;
+ const raw_ptr<Connection> connection_;
Connection::ErrorHandler old_error_handler_;
};
diff --git a/ui/gfx/x/window_cache.cc b/ui/gfx/x/window_cache.cc
new file mode 100644
index 0000000..9c60336
--- /dev/null
+++ b/ui/gfx/x/window_cache.cc
@@ -0,0 +1,401 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/x/window_cache.h"
+
+#include "base/containers/adapters.h"
+#include "base/containers/contains.h"
+#include "base/containers/cxx20_erase_vector.h"
+#include "base/functional/bind.h"
+#include "base/notreached.h"
+#include "base/ranges/algorithm.h"
+#include "base/run_loop.h"
+#include "base/task/single_thread_task_runner.h"
+#include "base/time/time.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/event.h"
+#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/x11_window_event_manager.h"
+#include "ui/gfx/x/xproto.h"
+
+namespace x11 {
+
+const base::TimeDelta kDestroyTimerInterval = base::Seconds(3);
+
+Window GetWindowAtPoint(const gfx::Point& point_px,
+ const base::flat_set<Window>* ignore) {
+ auto* connection = Connection::Get();
+ Window root = connection->default_root();
+
+ if (!WindowCache::instance()) {
+ auto instance =
+ std::make_unique<WindowCache>(connection, connection->default_root());
+ auto* cache = instance.get();
+ cache->BeginDestroyTimer(std::move(instance));
+ }
+
+ auto* instance = WindowCache::instance();
+ instance->WaitUntilReady();
+ return instance->GetWindowAtPoint(point_px, root, ignore);
+}
+
+ScopedShapeEventSelector::ScopedShapeEventSelector(Connection* connection,
+ Window window)
+ : connection_(connection), window_(window) {
+ connection_->shape().SelectInput(
+ {.destination_window = window_, .enable = true}).IgnoreError();
+}
+
+ScopedShapeEventSelector::~ScopedShapeEventSelector() {
+ connection_->shape().SelectInput(
+ {.destination_window = window_, .enable = false}).IgnoreError();
+}
+
+WindowCache::WindowInfo::WindowInfo() = default;
+
+WindowCache::WindowInfo::~WindowInfo() = default;
+
+// static
+WindowCache* WindowCache::instance_ = nullptr;
+
+WindowCache::WindowCache(Connection* connection, Window root)
+ : connection_(connection),
+ root_(root),
+ gtk_frame_extents_(GetAtom("_GTK_FRAME_EXTENTS")) {
+ DCHECK(!instance_) << "Only one WindowCache should be active at a time";
+ instance_ = this;
+
+ connection_->AddEventObserver(this);
+
+ // We select for SubstructureNotify events on all windows (to receive
+ // CreateNotify events), which will cause events to be sent for all child
+ // windows. This means we need to additionally select for StructureNotify
+ // changes for the root window.
+ root_events_ =
+ std::make_unique<XScopedEventSelector>(root_, EventMask::StructureNotify);
+ AddWindow(root_, Window::None);
+}
+
+WindowCache::~WindowCache() {
+ connection_->RemoveEventObserver(this);
+
+ DCHECK_EQ(instance_, this);
+ instance_ = nullptr;
+}
+
+void WindowCache::WaitUntilReady() {
+ auto& events = connection_->events();
+ size_t event = 0;
+ while (!pending_requests_.empty()) {
+ connection_->Flush();
+ for (size_t pending = pending_requests_.size(); pending;) {
+ if (event < events.size() &&
+ pending_requests_.front().AfterEvent(events[event])) {
+ OnEvent(events[event++]);
+ } else {
+ pending_requests_.front().DispatchNow();
+ --pending;
+ }
+ }
+ }
+ if (event)
+ last_processed_event_ = events[event - 1].sequence();
+}
+
+void WindowCache::BeginDestroyTimer(std::unique_ptr<WindowCache> self) {
+ DCHECK_EQ(this, self.get());
+ delete_when_destroy_timer_fires_ = false;
+ base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
+ FROM_HERE,
+ base::BindOnce(&WindowCache::OnDestroyTimerExpired,
+ base::Unretained(this), std::move(self)),
+ kDestroyTimerInterval);
+}
+
+void WindowCache::SyncForTest() {
+ do {
+ // Perform a blocking sync to prevent spinning while waiting for replies.
+ connection_->Sync();
+ connection_->DispatchAll();
+ } while (!pending_requests_.empty());
+}
+
+Window WindowCache::GetWindowAtPoint(gfx::Point point_px,
+ Window window,
+ const base::flat_set<Window>* ignore) {
+ delete_when_destroy_timer_fires_ = true;
+ if (ignore && ignore->contains(window))
+ return Window::None;
+ auto* info = GetInfo(window);
+ if (!info || !info->mapped)
+ return Window::None;
+
+ gfx::Rect rect(info->x_px, info->y_px, info->width_px, info->height_px);
+ rect.Outset(info->border_width_px);
+ rect.Inset(info->gtk_frame_extents_px);
+ if (!rect.Contains(point_px))
+ return Window::None;
+
+ point_px -= gfx::Vector2d(info->x_px, info->y_px);
+ if (info->bounding_rects_px && info->input_rects_px) {
+ for (const auto& rects : {info->bounding_rects_px, info->input_rects_px}) {
+ if (!base::ranges::any_of(*rects, [&point_px](const Rectangle& x_rect) {
+ gfx::Rect rect{x_rect.x, x_rect.y, x_rect.width, x_rect.height};
+ return rect.Contains(point_px);
+ })) {
+ return Window::None;
+ }
+ }
+ }
+
+ for (Window child : base::Reversed(info->children)) {
+ Window ret = GetWindowAtPoint(point_px, child, ignore);
+ if (ret != Window::None)
+ return ret;
+ }
+ if (info->has_wm_name)
+ return window;
+ return Window::None;
+}
+
+void WindowCache::OnEvent(const Event& event) {
+ // Ignore events that we've already processed.
+ if (last_processed_event_ &&
+ CompareSequenceIds(event.sequence(), *last_processed_event_) <= 0) {
+ return;
+ }
+ last_processed_event_ = absl::nullopt;
+
+ // Ignore events sent by clients since the server will send everything
+ // we need and client events may have different semantics (eg.
+ // ConfigureNotifyEvents are parent-relative if sent by the server but
+ // root-relative when sent by the WM).
+ if (event.send_event())
+ return;
+
+ if (auto* configure = event.As<ConfigureNotifyEvent>()) {
+ if (auto* info = GetInfo(configure->window)) {
+ info->x_px = configure->x;
+ info->y_px = configure->y;
+ info->width_px = configure->width;
+ info->height_px = configure->height;
+ info->border_width_px = configure->border_width;
+ if (auto* siblings = GetChildren(info->parent)) {
+ Window window = configure->window;
+ Window above = configure->above_sibling;
+ auto src = base::ranges::find(*siblings, window);
+ auto dst = base::ranges::find(*siblings, above);
+ auto end = siblings->end();
+ if (src != end && (dst != end || above == Window::None)) {
+ dst = above == Window::None ? siblings->begin() : ++dst;
+ if (src < dst)
+ std::rotate(src, src + 1, dst);
+ else if (src > dst)
+ std::rotate(dst, src, src + 1);
+ }
+ }
+ }
+ } else if (auto* property = event.As<PropertyNotifyEvent>()) {
+ if (auto* info = GetInfo(property->window)) {
+ if (property->atom == Atom::WM_NAME) {
+ info->has_wm_name = property->state != Property::Delete;
+ } else if (property->atom == gtk_frame_extents_) {
+ if (property->state == Property::Delete)
+ info->gtk_frame_extents_px = gfx::Insets();
+ else
+ GetProperty(property->window, gtk_frame_extents_, 4);
+ }
+ }
+ } else if (auto* create = event.As<CreateNotifyEvent>()) {
+ if (auto* info = GetInfo(create->parent)) {
+ info->children.push_back(create->window);
+ AddWindow(create->window, create->parent);
+ }
+ } else if (auto* destroy = event.As<DestroyNotifyEvent>()) {
+ if (auto* info = GetInfo(destroy->window)) {
+ if (auto* siblings = GetChildren(info->parent))
+ base::Erase(*siblings, destroy->window);
+ windows_.erase(destroy->window);
+ }
+ } else if (auto* map = event.As<MapNotifyEvent>()) {
+ if (auto* info = GetInfo(map->window))
+ info->mapped = true;
+ } else if (auto* unmap = event.As<UnmapNotifyEvent>()) {
+ if (auto* info = GetInfo(unmap->window))
+ info->mapped = false;
+ } else if (auto* reparent = event.As<ReparentNotifyEvent>()) {
+ if (auto* info = GetInfo(reparent->window)) {
+ if (auto* old_siblings = GetChildren(info->parent))
+ base::Erase(*old_siblings, reparent->window);
+ if (auto* new_siblings = GetChildren(reparent->parent))
+ new_siblings->push_back(reparent->window);
+ info->parent = reparent->parent;
+ }
+ } else if (auto* gravity = event.As<GravityNotifyEvent>()) {
+ if (auto* info = GetInfo(gravity->window)) {
+ info->x_px = gravity->x;
+ info->y_px = gravity->y;
+ }
+ } else if (auto* circulate = event.As<CirculateEvent>()) {
+ if (auto* info = GetInfo(circulate->window)) {
+ if (auto* siblings = GetChildren(info->parent)) {
+ base::Erase(*siblings, circulate->window);
+ if (circulate->place == Place::OnTop)
+ siblings->push_back(circulate->window);
+ else
+ siblings->insert(siblings->begin(), circulate->window);
+ }
+ }
+ } else if (auto* shape = event.As<Shape::NotifyEvent>()) {
+ Window window = shape->affected_window;
+ Shape::Sk kind = shape->shape_kind;
+ if (kind != Shape::Sk::Clip && base::Contains(windows_, window)) {
+ AddRequest(connection_->shape().GetRectangles(window, kind),
+ &WindowCache::OnGetRectanglesResponse, window, kind);
+ }
+ }
+}
+
+void WindowCache::AddWindow(Window window, Window parent) {
+ if (base::Contains(windows_, window))
+ return;
+ WindowInfo& info = windows_[window];
+ info.parent = parent;
+ // Events must be selected before getting the initial window info to
+ // prevent race conditions.
+ info.events = std::make_unique<XScopedEventSelector>(
+ window, EventMask::SubstructureNotify | EventMask::PropertyChange);
+
+ AddRequest(connection_->GetWindowAttributes(window),
+ &WindowCache::OnGetWindowAttributesResponse, window);
+ AddRequest(connection_->GetGeometry(window),
+ &WindowCache::OnGetGeometryResponse, window);
+ AddRequest(connection_->QueryTree(window), &WindowCache::OnQueryTreeResponse,
+ window);
+
+ GetProperty(window, Atom::WM_NAME, 1);
+ GetProperty(window, gtk_frame_extents_, 4);
+
+ auto& shape = connection_->shape();
+ if (shape.present()) {
+ info.shape_events =
+ std::make_unique<ScopedShapeEventSelector>(connection_, window);
+
+ for (auto kind : {Shape::Sk::Bounding, Shape::Sk::Input}) {
+ AddRequest(shape.GetRectangles(window, kind),
+ &WindowCache::OnGetRectanglesResponse, window, kind);
+ }
+ }
+}
+
+WindowCache::WindowInfo* WindowCache::GetInfo(Window window) {
+ auto it = windows_.find(window);
+ if (it == windows_.end())
+ return nullptr;
+ return &it->second;
+}
+
+std::vector<Window>* WindowCache::GetChildren(Window window) {
+ if (auto* info = GetInfo(window))
+ return &info->children;
+ return nullptr;
+}
+
+void WindowCache::GetProperty(Window window, Atom property, uint32_t length) {
+ AddRequest(
+ connection_->GetProperty(
+ {.window = window, .property = property, .long_length = length}),
+ &WindowCache::OnGetPropertyResponse, window, property);
+}
+
+WindowCache::WindowInfo* WindowCache::OnResponse(Window window,
+ bool has_reply) {
+ pending_requests_.pop_front();
+ if (!has_reply) {
+ windows_.erase(window);
+ return nullptr;
+ }
+ auto it = windows_.find(window);
+ if (it == windows_.end())
+ return nullptr;
+ return &it->second;
+}
+
+void WindowCache::OnGetWindowAttributesResponse(
+ Window window,
+ GetWindowAttributesResponse response) {
+ if (auto* info = OnResponse(window, response.reply.get()))
+ info->mapped = response->map_state != MapState::Unmapped;
+}
+
+void WindowCache::OnGetGeometryResponse(Window window,
+ GetGeometryResponse response) {
+ if (auto* info = OnResponse(window, response.reply.get())) {
+ info->x_px = response->x;
+ info->y_px = response->y;
+ info->width_px = response->width;
+ info->height_px = response->height;
+ }
+}
+
+void WindowCache::OnQueryTreeResponse(Window window,
+ QueryTreeResponse response) {
+ if (auto* info = OnResponse(window, response.reply.get())) {
+ info->parent = response->parent;
+ info->children = std::move(response->children);
+ for (auto child : info->children)
+ AddWindow(child, window);
+ }
+}
+
+void WindowCache::OnGetPropertyResponse(Window window,
+ Atom atom,
+ GetPropertyResponse response) {
+ if (auto* info = OnResponse(window, response.reply.get())) {
+ if (atom == Atom::WM_NAME) {
+ info->has_wm_name = response->format;
+ } else if (atom == gtk_frame_extents_) {
+ if (response->format == CHAR_BIT * sizeof(int32_t) &&
+ response->value_len == 4) {
+ const int32_t* frame_extents = response->value->front_as<int32_t>();
+ info->gtk_frame_extents_px =
+ gfx::Insets::TLBR(frame_extents[2], frame_extents[0],
+ frame_extents[3], frame_extents[1]);
+ } else {
+ info->gtk_frame_extents_px = gfx::Insets();
+ }
+ }
+ }
+}
+
+void WindowCache::OnGetRectanglesResponse(
+ Window window,
+ Shape::Sk kind,
+ Shape::GetRectanglesResponse response) {
+ if (auto* info = OnResponse(window, response.reply.get())) {
+ switch (kind) {
+ case Shape::Sk::Bounding:
+ info->bounding_rects_px = std::move(response->rectangles);
+ break;
+ case Shape::Sk::Clip:
+ NOTREACHED();
+ break;
+ case Shape::Sk::Input:
+ info->input_rects_px = std::move(response->rectangles);
+ break;
+ }
+ }
+}
+
+void WindowCache::OnDestroyTimerExpired(std::unique_ptr<WindowCache> self) {
+ if (!delete_when_destroy_timer_fires_)
+ return; // destroy `this`
+
+ BeginDestroyTimer(std::move(self));
+}
+
+} // namespace x11
diff --git a/ui/gfx/x/window_cache.h b/ui/gfx/x/window_cache.h
new file mode 100644
index 0000000..f241d6c
--- /dev/null
+++ b/ui/gfx/x/window_cache.h
@@ -0,0 +1,178 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GFX_X_WINDOW_CACHE_H_
+#define UI_GFX_X_WINDOW_CACHE_H_
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+#include "base/component_export.h"
+#include "base/containers/circular_deque.h"
+#include "base/containers/flat_set.h"
+#include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/future.h"
+#include "ui/gfx/x/shape.h"
+#include "ui/gfx/x/xproto.h"
+
+namespace x11 {
+
+COMPONENT_EXPORT(X11)
+Window GetWindowAtPoint(const gfx::Point& point_px,
+ const base::flat_set<Window>* ignore = nullptr);
+
+class Connection;
+class XScopedEventSelector;
+
+class ScopedShapeEventSelector {
+ public:
+ ScopedShapeEventSelector(Connection* connection, Window window);
+ ~ScopedShapeEventSelector();
+
+ private:
+ const raw_ptr<Connection> connection_;
+ const Window window_;
+};
+
+// Maintains a cache of the state of all X11 windows.
+class COMPONENT_EXPORT(X11) WindowCache : public EventObserver {
+ public:
+ struct WindowInfo {
+ WindowInfo();
+ ~WindowInfo();
+
+ Window parent = Window::None;
+ bool mapped = false;
+
+ // Properties
+ bool has_wm_name = false;
+ gfx::Insets gtk_frame_extents_px;
+
+ int16_t x_px = 0;
+ int16_t y_px = 0;
+ uint16_t width_px = 0;
+ uint16_t height_px = 0;
+ uint16_t border_width_px = 0;
+
+ // Child windows listed in lowest-to-highest stacking order.
+ // Although it is possible to restack windows, it is uncommon to do so,
+ // so we store children in a vector instead of a node-based structure.
+ std::vector<Window> children;
+
+ absl::optional<std::vector<Rectangle>> bounding_rects_px;
+ absl::optional<std::vector<Rectangle>> input_rects_px;
+
+ std::unique_ptr<XScopedEventSelector> events;
+ std::unique_ptr<ScopedShapeEventSelector> shape_events;
+ };
+
+ static WindowCache* instance() { return instance_; }
+
+ // If `track_events` is true, the WindowCache will keep the cache state synced
+ // with the server's state over time. It may be set to false if the cache is
+ // short-lived, if only a single GetWindowAtPoint call is made.
+ WindowCache(Connection* connection, Window root);
+ WindowCache(const WindowCache&) = delete;
+ WindowCache& operator=(const WindowCache&) = delete;
+ ~WindowCache() override;
+
+ // Returns the window at the specified point or Window::None if no match could
+ // be found. `point_px` is in coordinates of the parent of `window`.
+ Window GetWindowAtPoint(gfx::Point point_px,
+ Window window,
+ const base::flat_set<Window>* ignore = nullptr);
+
+ // Blocks until all outstanding requests are processed.
+ void WaitUntilReady();
+
+ // Destroys |self| if no calls to GetWindowAtPoint() are made within
+ // a time window.
+ void BeginDestroyTimer(std::unique_ptr<WindowCache> self);
+
+ void SyncForTest();
+
+ const std::unordered_map<Window, WindowInfo>& windows() const {
+ return windows_;
+ }
+
+ private:
+ // This helper reduces boilerplate when adding requests.
+ template <typename Future, typename Callback, typename... Args>
+ void AddRequest(Future&& future, Callback&& callback, Args&&... args) {
+ future.OnResponse(base::BindOnce(callback, weak_factory_.GetWeakPtr(),
+ std::forward<Args>(args)...));
+ pending_requests_.push_back(std::move(future));
+ }
+
+ // EventObserver:
+ void OnEvent(const Event& event) override;
+
+ // Start caching the window tree starting at `window`. `parent` is set as
+ // the initial parent in the cache state.
+ void AddWindow(Window window, Window parent);
+
+ // Returns the WindowInfo for `window` or nullptr if `window` is not cached.
+ WindowInfo* GetInfo(Window window);
+
+ // Returns a vector of child windows or nullptr if `window` is not cached.
+ std::vector<Window>* GetChildren(Window window);
+
+ // Makes a GetProperty request with a callback to OnGetPropertyResponse().
+ void GetProperty(Window window, Atom property, uint32_t length);
+
+ // Common response handler that's called at the beginning of each On*Response.
+ // Returns the WindowInfo for `window` or nullptr if `window` is not cached
+ // or `has_reply` is false.
+ WindowInfo* OnResponse(Window window, bool has_reply);
+
+ void OnGetWindowAttributesResponse(Window window,
+ GetWindowAttributesResponse response);
+
+ void OnGetGeometryResponse(Window window, GetGeometryResponse response);
+
+ void OnQueryTreeResponse(Window window, QueryTreeResponse response);
+
+ void OnGetPropertyResponse(Window window,
+ Atom atom,
+ GetPropertyResponse response);
+
+ void OnGetRectanglesResponse(Window window,
+ Shape::Sk kind,
+ Shape::GetRectanglesResponse response);
+
+ void OnDestroyTimerExpired(std::unique_ptr<WindowCache> self);
+
+ static WindowCache* instance_;
+
+ const raw_ptr<Connection> connection_;
+ const Window root_;
+ const Atom gtk_frame_extents_;
+ std::unique_ptr<XScopedEventSelector> root_events_;
+
+ std::unordered_map<Window, WindowInfo> windows_;
+
+ base::circular_deque<FutureBase> pending_requests_;
+
+ // The latest event processed out-of-order, or nullopt if the latest event was
+ // processed in order.
+ absl::optional<uint32_t> last_processed_event_;
+
+ // True iff GetWindowAtPoint() was called since the last timer interval.
+ bool delete_when_destroy_timer_fires_ = false;
+
+ // Although only one instance of WindowCache may be created at a time, the
+ // instance will be created and destroyed as needed, so WeakPtrs are still
+ // necessary.
+ base::WeakPtrFactory<WindowCache> weak_factory_{this};
+};
+
+} // namespace x11
+
+#endif // UI_GFX_X_WINDOW_CACHE_H_
diff --git a/ui/gfx/x/window_cache_unittest.cc b/ui/gfx/x/window_cache_unittest.cc
new file mode 100644
index 0000000..2199dda
--- /dev/null
+++ b/ui/gfx/x/window_cache_unittest.cc
@@ -0,0 +1,437 @@
+// Copyright 2022 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gfx/x/window_cache.h"
+
+#include "base/memory/raw_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/x/connection.h"
+#include "ui/gfx/x/future.h"
+#include "ui/gfx/x/x11_atom_cache.h"
+#include "ui/gfx/x/xproto_util.h"
+
+namespace x11 {
+
+class WindowCacheTest : public testing::Test {
+ public:
+ ~WindowCacheTest() override = default;
+
+ protected:
+ void ResetCache() {
+ cache_.reset();
+ cache_ = std::make_unique<WindowCache>(connection_, root_);
+ cache_->SyncForTest();
+ }
+
+ Window CreateWindow(Window parent) {
+ Window window = connection_->GenerateId<Window>();
+ connection_->CreateWindow({
+ .wid = window,
+ .parent = parent,
+ .width = 512,
+ .height = 1024,
+ .override_redirect = static_cast<Bool32>(true),
+ });
+ return window;
+ }
+
+ Connection* connection() { return connection_; }
+
+ Window root() const { return root_; }
+
+ Window root_container() const { return root_container_; }
+
+ WindowCache* cache() { return cache_.get(); }
+
+ private:
+ void SetUp() override {
+ connection_ = Connection::Get();
+ root_container_ = CreateWindow(connection_->default_root());
+ root_ = CreateWindow(root_container_);
+ ResetCache();
+ }
+
+ void TearDown() override {
+ cache_.reset();
+ connection_->DestroyWindow({root_}).Sync();
+ connection_->DestroyWindow({root_container_}).Sync();
+ root_ = Window::None;
+ root_container_ = Window::None;
+ connection_ = nullptr;
+ }
+
+ raw_ptr<Connection> connection_;
+ Window root_container_ = Window::None;
+ Window root_ = Window::None;
+ std::unique_ptr<WindowCache> cache_;
+};
+
+// Ensure creating the cache doesn't timeout.
+TEST_F(WindowCacheTest, Basic) {
+ const WindowCache::WindowInfo& info = cache()->windows().at(root());
+ EXPECT_EQ(info.parent, root_container());
+ EXPECT_FALSE(info.mapped);
+ EXPECT_EQ(info.x_px, 0);
+ EXPECT_EQ(info.y_px, 0);
+ EXPECT_EQ(info.width_px, 512);
+ EXPECT_EQ(info.height_px, 1024);
+ EXPECT_EQ(info.border_width_px, 0);
+ EXPECT_TRUE(info.children.empty());
+}
+
+TEST_F(WindowCacheTest, ConfigureNotify) {
+ connection()->ConfigureWindow({.window = root(),
+ .x = 10,
+ .y = 10,
+ .width = 20,
+ .height = 20,
+ .border_width = 5});
+ cache()->SyncForTest();
+ const WindowCache::WindowInfo& info = cache()->windows().at(root());
+ EXPECT_EQ(info.x_px, 10);
+ EXPECT_EQ(info.y_px, 10);
+ EXPECT_EQ(info.width_px, 20);
+ EXPECT_EQ(info.height_px, 20);
+ EXPECT_EQ(info.border_width_px, 5);
+}
+
+TEST_F(WindowCacheTest, CreateAndDestroyNotify) {
+ Window r = root();
+ Window a = CreateWindow(r);
+ Window aa = CreateWindow(a);
+ Window ab = CreateWindow(a);
+ Window b = CreateWindow(r);
+ Window ba = CreateWindow(b);
+ Window bb = CreateWindow(b);
+
+ cache()->SyncForTest();
+ EXPECT_EQ(cache()->windows().at(r).children, (std::vector<Window>{a, b}));
+ EXPECT_EQ(cache()->windows().at(a).children, (std::vector<Window>{aa, ab}));
+ EXPECT_EQ(cache()->windows().at(b).children, (std::vector<Window>{ba, bb}));
+
+ connection()->DestroyWindow(ab);
+ connection()->DestroyWindow(ba);
+ cache()->SyncForTest();
+ EXPECT_EQ(cache()->windows().at(r).children, (std::vector<Window>{a, b}));
+ EXPECT_EQ(cache()->windows().at(a).children, (std::vector<Window>{aa}));
+ EXPECT_EQ(cache()->windows().at(b).children, (std::vector<Window>{bb}));
+}
+
+TEST_F(WindowCacheTest, Restack) {
+ auto restack = [&](Window window, Window sibling, bool above) {
+ connection()->ConfigureWindow(
+ {.window = window,
+ .sibling = sibling,
+ .stack_mode = above ? StackMode::Above : StackMode::Below});
+ cache()->SyncForTest();
+ };
+ Window a = CreateWindow(root());
+ Window b = CreateWindow(root());
+ Window c = CreateWindow(root());
+ Window d = CreateWindow(root());
+ Window e = CreateWindow(root());
+ Window f = CreateWindow(root());
+
+ cache()->SyncForTest();
+ auto& windows = cache()->windows().at(root()).children;
+ EXPECT_EQ(windows, (std::vector<Window>{a, b, c, d, e, f}));
+
+ restack(b, e, true);
+ EXPECT_EQ(windows, (std::vector<Window>{a, c, d, e, b, f}));
+
+ restack(f, a, false);
+ EXPECT_EQ(windows, (std::vector<Window>{f, a, c, d, e, b}));
+
+ restack(c, d, true);
+ EXPECT_EQ(windows, (std::vector<Window>{f, a, d, c, e, b}));
+
+ restack(d, b, true);
+ EXPECT_EQ(windows, (std::vector<Window>{f, a, c, e, b, d}));
+
+ restack(e, c, false);
+ EXPECT_EQ(windows, (std::vector<Window>{f, a, e, c, b, d}));
+
+ restack(b, a, false);
+ EXPECT_EQ(windows, (std::vector<Window>{f, b, a, e, c, d}));
+
+ // Test a configure event where the stacking doesn't change.
+ connection()->ConfigureWindow({.window = a, .width = 100});
+ cache()->SyncForTest();
+ EXPECT_EQ(windows, (std::vector<Window>{f, b, a, e, c, d}));
+}
+
+TEST_F(WindowCacheTest, MapAndUnmapNotify) {
+ Window window = CreateWindow(root());
+ cache()->SyncForTest();
+ auto& info = cache()->windows().at(window);
+ EXPECT_FALSE(info.mapped);
+
+ connection()->MapWindow(window);
+ cache()->SyncForTest();
+ EXPECT_TRUE(info.mapped);
+
+ connection()->UnmapWindow(window);
+ cache()->SyncForTest();
+ EXPECT_FALSE(info.mapped);
+}
+
+TEST_F(WindowCacheTest, ReparentNotify) {
+ Window r = root();
+ Window a = CreateWindow(r);
+ Window b = CreateWindow(r);
+ Window w = CreateWindow(b);
+
+ cache()->SyncForTest();
+ auto& info_a = cache()->windows().at(a);
+ auto& info_b = cache()->windows().at(b);
+ auto& info_w = cache()->windows().at(w);
+ EXPECT_EQ(info_a.children, (std::vector<Window>{}));
+ EXPECT_EQ(info_b.children, (std::vector<Window>{w}));
+ EXPECT_EQ(info_w.parent, b);
+
+ connection()->ReparentWindow(w, a);
+ cache()->SyncForTest();
+ EXPECT_EQ(info_a.children, (std::vector<Window>{w}));
+ EXPECT_EQ(info_b.children, (std::vector<Window>{}));
+ EXPECT_EQ(info_w.parent, a);
+}
+
+TEST_F(WindowCacheTest, GravityNotify) {
+ Window parent = CreateWindow(root());
+ Window child = connection()->GenerateId<Window>();
+ connection()->CreateWindow({
+ .wid = child,
+ .parent = parent,
+ .x = 512,
+ .y = 1024,
+ .width = 10,
+ .height = 10,
+ .win_gravity = Gravity::SouthEast,
+ .override_redirect = static_cast<Bool32>(true),
+ });
+
+ cache()->SyncForTest();
+ auto& info = cache()->windows().at(child);
+ EXPECT_EQ(info.x_px, 512);
+ EXPECT_EQ(info.y_px, 1024);
+
+ connection()->ConfigureWindow(
+ {.window = parent, .width = 256, .height = 512});
+ cache()->SyncForTest();
+ EXPECT_EQ(info.x_px, 256);
+ EXPECT_EQ(info.y_px, 512);
+}
+
+TEST_F(WindowCacheTest, CirculateNotify) {
+ Window a = CreateWindow(root());
+ Window b = CreateWindow(root());
+ Window c = CreateWindow(root());
+ Window d = CreateWindow(root());
+ for (Window w : {a, b, c, d})
+ connection()->MapWindow(w);
+
+ cache()->SyncForTest();
+ auto& windows = cache()->windows().at(root()).children;
+ EXPECT_EQ(windows, (std::vector<Window>{a, b, c, d}));
+
+ connection()->CirculateWindow(Circulate::RaiseLowest, root());
+ cache()->SyncForTest();
+ EXPECT_EQ(windows, (std::vector<Window>{b, c, d, a}));
+
+ connection()->CirculateWindow(Circulate::LowerHighest, root());
+ cache()->SyncForTest();
+ EXPECT_EQ(windows, (std::vector<Window>{a, b, c, d}));
+}
+
+TEST_F(WindowCacheTest, ShapeExtension) {
+ auto& shape = connection()->shape();
+ if (!shape.present())
+ return;
+
+ const WindowCache::WindowInfo& info = cache()->windows().at(root());
+ EXPECT_EQ(info.bounding_rects_px,
+ (std::vector<Rectangle>{{0, 0, 512, 1024}}));
+ EXPECT_EQ(info.input_rects_px, (std::vector<Rectangle>{{0, 0, 512, 1024}}));
+
+ std::vector<Rectangle> bounding_rects{{10, 10, 100, 100}};
+ std::vector<Rectangle> input_rects{{20, 20, 10, 10}, {50, 50, 10, 10}};
+ shape.Rectangles({.operation = Shape::So::Set,
+ .destination_kind = Shape::Sk::Bounding,
+ .destination_window = root(),
+ .rectangles = bounding_rects});
+ shape.Rectangles({.operation = Shape::So::Set,
+ .destination_kind = Shape::Sk::Input,
+ .destination_window = root(),
+ .rectangles = input_rects});
+ cache()->SyncForTest();
+ EXPECT_EQ(info.bounding_rects_px, bounding_rects);
+ EXPECT_EQ(info.input_rects_px, input_rects);
+}
+
+TEST_F(WindowCacheTest, WmName) {
+ const WindowCache::WindowInfo& info = cache()->windows().at(root());
+ EXPECT_FALSE(info.has_wm_name);
+
+ SetStringProperty(root(), Atom::WM_NAME, Atom::STRING, "Foo");
+ cache()->SyncForTest();
+ EXPECT_TRUE(info.has_wm_name);
+
+ connection()->DeleteProperty(root(), Atom::WM_NAME);
+ cache()->SyncForTest();
+ EXPECT_FALSE(info.has_wm_name);
+}
+
+TEST_F(WindowCacheTest, GtkFrameExtents) {
+ const WindowCache::WindowInfo& info = cache()->windows().at(root());
+ EXPECT_EQ(info.gtk_frame_extents_px, gfx::Insets());
+
+ const Atom gtk_frame_extents = GetAtom("_GTK_FRAME_EXTENTS");
+ SetArrayProperty(root(), gtk_frame_extents, Atom::CARDINAL,
+ std::vector<uint32_t>{1, 2, 3, 4});
+ cache()->SyncForTest();
+ EXPECT_EQ(info.gtk_frame_extents_px, gfx::Insets::TLBR(3, 1, 4, 2));
+
+ connection()->DeleteProperty(root(), gtk_frame_extents);
+ cache()->SyncForTest();
+ EXPECT_EQ(info.gtk_frame_extents_px, gfx::Insets());
+
+ // Make sure malformed values don't get cached.
+ SetArrayProperty(root(), gtk_frame_extents, Atom::CARDINAL,
+ std::vector<uint32_t>{1, 2});
+ cache()->SyncForTest();
+ EXPECT_EQ(info.gtk_frame_extents_px, gfx::Insets());
+
+ SetArrayProperty(root(), gtk_frame_extents, Atom::CARDINAL,
+ std::vector<uint8_t>{1, 2, 3, 4});
+ cache()->SyncForTest();
+ EXPECT_EQ(info.gtk_frame_extents_px, gfx::Insets());
+}
+
+TEST_F(WindowCacheTest, GetWindowAtPoint) {
+ // Basic test on an undecorated, unobscured window.
+ connection()->MapWindow(root());
+ SetStringProperty(root(), Atom::WM_NAME, Atom::STRING, "root");
+ cache()->SyncForTest();
+ EXPECT_EQ(cache()->GetWindowAtPoint({100, 100}, root()), root());
+
+ // Unmapped windows are hidden.
+ connection()->UnmapWindow(root());
+ cache()->SyncForTest();
+ EXPECT_EQ(cache()->GetWindowAtPoint({100, 100}, root()), Window::None);
+ connection()->MapWindow(root());
+
+ // Unnamed windows should not be returned.
+ connection()->DeleteProperty(root(), Atom::WM_NAME);
+ cache()->SyncForTest();
+ EXPECT_EQ(cache()->GetWindowAtPoint({100, 100}, root()), Window::None);
+
+ // GetWindowAtPoint on an uncached window shouldn't crash.
+ Window does_not_exist = connection()->GenerateId<Window>();
+ EXPECT_EQ(cache()->GetWindowAtPoint({100, 100}, does_not_exist),
+ Window::None);
+
+ // Basic hit test.
+ Window a = CreateWindow(root());
+ connection()->ConfigureWindow({
+ .window = a,
+ .x = 100,
+ .y = 100,
+ .width = 100,
+ .height = 100,
+ });
+ connection()->MapWindow(a);
+ SetStringProperty(a, Atom::WM_NAME, Atom::STRING, "a");
+ cache()->SyncForTest();
+ EXPECT_EQ(cache()->GetWindowAtPoint({150, 150}, root()), a);
+ EXPECT_EQ(cache()->GetWindowAtPoint({50, 50}, root()), Window::None);
+
+ // Border hit test.
+ auto& shape = connection()->shape();
+ if (shape.present()) {
+ for (auto kind : {Shape::Sk::Bounding, Shape::Sk::Input}) {
+ shape.Rectangles(
+ {.destination_kind = kind,
+ .destination_window = a,
+ .rectangles = std::vector<Rectangle>{{0, 0, 300, 300}}});
+ }
+ }
+ cache()->SyncForTest();
+ EXPECT_EQ(cache()->GetWindowAtPoint({250, 250}, root()), Window::None);
+ connection()->ConfigureWindow({.window = a, .border_width = 100});
+ cache()->SyncForTest();
+ EXPECT_EQ(cache()->GetWindowAtPoint({250, 250}, root()), a);
+ connection()->ConfigureWindow({.window = a, .border_width = 0});
+ if (shape.present()) {
+ for (auto kind : {Shape::Sk::Bounding, Shape::Sk::Input})
+ shape.Mask({.destination_kind = kind, .destination_window = a});
+ }
+
+ // GTK_FRAME_EXTENTS insets the window bounds.
+ EXPECT_EQ(cache()->GetWindowAtPoint({125, 125}, root()), a);
+ const Atom gtk_frame_extents = GetAtom("_GTK_FRAME_EXTENTS");
+ SetArrayProperty(a, gtk_frame_extents, Atom::CARDINAL,
+ std::vector<uint32_t>{40, 40, 40, 40});
+ cache()->SyncForTest();
+ EXPECT_EQ(cache()->GetWindowAtPoint({125, 125}, root()), Window::None);
+ connection()->DeleteProperty(a, gtk_frame_extents);
+
+ // Hit test in XShape region.
+ if (shape.present()) {
+ EXPECT_EQ(cache()->GetWindowAtPoint({150, 150}, root()), a);
+ for (auto kind : {Shape::Sk::Bounding, Shape::Sk::Input}) {
+ // Set to an empty bounding shape.
+ shape.Rectangles({.destination_kind = kind, .destination_window = a});
+ cache()->SyncForTest();
+ EXPECT_EQ(cache()->GetWindowAtPoint({150, 150}, root()), Window::None);
+ shape.Mask({.destination_kind = kind, .destination_window = a});
+ }
+ }
+
+ // Test window stacking order.
+ Window b = CreateWindow(root());
+ connection()->ConfigureWindow({
+ .window = b,
+ .x = 100,
+ .y = 100,
+ .width = 100,
+ .height = 100,
+ });
+ connection()->MapWindow(b);
+ SetStringProperty(b, Atom::WM_NAME, Atom::STRING, "b");
+ cache()->SyncForTest();
+ EXPECT_EQ(cache()->GetWindowAtPoint({150, 150}, root()), b);
+
+ // Test window nesting.
+ Window c = CreateWindow(b);
+ connection()->ConfigureWindow({
+ .window = c,
+ .x = 0,
+ .y = 0,
+ .width = 100,
+ .height = 100,
+ });
+ connection()->MapWindow(c);
+ SetStringProperty(c, Atom::WM_NAME, Atom::STRING, "c");
+ connection()->DeleteProperty(b, Atom::WM_NAME);
+ cache()->SyncForTest();
+ EXPECT_EQ(cache()->GetWindowAtPoint({150, 150}, root()), c);
+}
+
+// Regression test for https://crbug.com/1316735
+// If both a parent and child window have a WM_NAME, the child window
+// should be returned by GetWindowAtPoint().
+TEST_F(WindowCacheTest, NestedWmName) {
+ connection()->MapWindow(root());
+ SetStringProperty(root(), Atom::WM_NAME, Atom::STRING, "root");
+
+ Window a = CreateWindow(root());
+ connection()->MapWindow(a);
+ SetStringProperty(a, Atom::WM_NAME, Atom::STRING, "a");
+
+ cache()->SyncForTest();
+ EXPECT_EQ(cache()->GetWindowAtPoint({100, 100}, root()), a);
+}
+
+} // namespace x11
diff --git a/ui/gfx/x/x11_atom_cache.cc b/ui/gfx/x/x11_atom_cache.cc
index a262069..0a626f9 100644
--- a/ui/gfx/x/x11_atom_cache.cc
+++ b/ui/gfx/x/x11_atom_cache.cc
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,7 +8,6 @@
#include <vector>
#include "base/check.h"
-#include "base/cxx17_backports.h"
#include "base/memory/singleton.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/future.h"
@@ -104,9 +103,10 @@
"_MOTIF_WM_HINTS",
"_NETSCAPE_URL",
"_NET_ACTIVE_WINDOW",
- "_NET_CLIENT_LIST_STACKING",
"_NET_CURRENT_DESKTOP",
"_NET_FRAME_EXTENTS",
+ "_NET_STARTUP_INFO",
+ "_NET_STARTUP_INFO_BEGIN",
"_NET_SUPPORTED",
"_NET_SUPPORTING_WM_CHECK",
"_NET_SYSTEM_TRAY_OPCODE",
@@ -170,7 +170,7 @@
"xwayland-touch",
};
-constexpr int kCacheCount = base::size(kAtomsToCache);
+constexpr int kCacheCount = std::size(kAtomsToCache);
} // namespace
diff --git a/ui/gfx/x/x11_atom_cache.h b/ui/gfx/x/x11_atom_cache.h
index 063b438..22632b3 100644
--- a/ui/gfx/x/x11_atom_cache.h
+++ b/ui/gfx/x/x11_atom_cache.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,7 +9,7 @@
#include <string>
#include "base/component_export.h"
-#include "base/macros.h"
+#include "base/memory/raw_ptr.h"
#include "ui/gfx/x/xproto.h"
namespace base {
@@ -48,7 +48,7 @@
// On failure, None is returned.
Atom GetAtom(const std::string&) const;
- Connection* connection_;
+ raw_ptr<Connection> connection_;
// Using std::map, as it is possible for thousands of atoms to be registered.
mutable std::map<std::string, Atom> cached_atoms_;
diff --git a/ui/gfx/x/x11_path.cc b/ui/gfx/x/x11_path.cc
index 9d4a2bb..00de675 100644
--- a/ui/gfx/x/x11_path.cc
+++ b/ui/gfx/x/x11_path.cc
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/x11_path.h b/ui/gfx/x/x11_path.h
index 6a44b2f..6f33d06 100644
--- a/ui/gfx/x/x11_path.h
+++ b/ui/gfx/x/x11_path.h
@@ -1,4 +1,4 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/x11_switches.cc b/ui/gfx/x/x11_switches.cc
deleted file mode 100644
index 9e53afd..0000000
--- a/ui/gfx/x/x11_switches.cc
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "ui/gfx/x/x11_switches.h"
-
-namespace switches {
-
-// Which X11 display to connect to. Emulates the GTK+ "--display=" command line
-// argument.
-const char kX11Display[] = "display";
-
-// Disables MIT-SHM extension.
-const char kNoXshm[] = "no-xshm";
-
-} // namespace switches
diff --git a/ui/gfx/x/x11_switches.h b/ui/gfx/x/x11_switches.h
deleted file mode 100644
index 2df00e5..0000000
--- a/ui/gfx/x/x11_switches.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_GFX_X_X11_SWITCHES_H_
-#define UI_GFX_X_X11_SWITCHES_H_
-
-#include "base/component_export.h"
-
-namespace switches {
-
-COMPONENT_EXPORT(X11) extern const char kX11Display[];
-
-COMPONENT_EXPORT(X11) extern const char kNoXshm[];
-
-} // namespace switches
-
-#endif // UI_GFX_X_X11_SWITCHES_H_
diff --git a/ui/gfx/x/x11_window_event_manager.cc b/ui/gfx/x/x11_window_event_manager.cc
index ac86642..fecac8f 100644
--- a/ui/gfx/x/x11_window_event_manager.cc
+++ b/ui/gfx/x/x11_window_event_manager.cc
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/x11_window_event_manager.h b/ui/gfx/x/x11_window_event_manager.h
index 50e5855..312f734 100644
--- a/ui/gfx/x/x11_window_event_manager.h
+++ b/ui/gfx/x/x11_window_event_manager.h
@@ -1,4 +1,4 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,7 +8,6 @@
#include <map>
#include "base/component_export.h"
-#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "ui/gfx/x/connection.h"
diff --git a/ui/gfx/x/xlib.h b/ui/gfx/x/xlib.h
index 1c26ffd..fedba1c 100644
--- a/ui/gfx/x/xlib.h
+++ b/ui/gfx/x/xlib.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/xlib_support.cc b/ui/gfx/x/xlib_support.cc
index 281c318..35f995e 100644
--- a/ui/gfx/x/xlib_support.cc
+++ b/ui/gfx/x/xlib_support.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -32,7 +32,7 @@
} // namespace
-DISABLE_CFI_ICALL
+DISABLE_CFI_DLSYM
void InitXlib() {
auto* xlib_loader = GetXlibLoader();
if (xlib_loader->loaded())
@@ -53,17 +53,17 @@
SetXlibErrorHandler();
}
-DISABLE_CFI_ICALL
+DISABLE_CFI_DLSYM
void SetXlibErrorHandler() {
GetXlibLoader()->XSetErrorHandler(XlibErrorHandler);
}
-DISABLE_CFI_ICALL
+DISABLE_CFI_DLSYM
void XlibFree(void* data) {
GetXlibLoader()->XFree(data);
}
-DISABLE_CFI_ICALL
+DISABLE_CFI_DLSYM
XlibDisplay::XlibDisplay(const std::string& address) {
InitXlib();
@@ -71,7 +71,7 @@
: address.c_str());
}
-DISABLE_CFI_ICALL
+DISABLE_CFI_DLSYM
XlibDisplay::~XlibDisplay() {
if (!display_)
return;
@@ -81,10 +81,12 @@
// events, they will just queue up and leak memory. This check makes sure
// |display_| never had any pending events before it is closed.
CHECK(!loader->XPending(display_));
- loader->XCloseDisplay(display_);
+ // ExtractAsDangling clears the underlying pointer and returns another raw_ptr
+ // instance that is allowed to dangle.
+ loader->XCloseDisplay(display_.ExtractAsDangling());
}
-DISABLE_CFI_ICALL
+DISABLE_CFI_DLSYM
XlibDisplayWrapper::XlibDisplayWrapper(struct _XDisplay* display,
XlibDisplayType type)
: display_(display), type_(type) {
@@ -94,7 +96,7 @@
GetXlibLoader()->XSynchronize(display_, true);
}
-DISABLE_CFI_ICALL
+DISABLE_CFI_DLSYM
XlibDisplayWrapper::~XlibDisplayWrapper() {
if (!display_)
return;
@@ -119,7 +121,7 @@
return *this;
}
-DISABLE_CFI_ICALL
+DISABLE_CFI_DLSYM
struct xcb_connection_t* XlibDisplayWrapper::GetXcbConnection() {
return GetXlibXcbLoader()->XGetXCBConnection(display_);
}
diff --git a/ui/gfx/x/xlib_support.h b/ui/gfx/x/xlib_support.h
index 26accef..bef5db8 100644
--- a/ui/gfx/x/xlib_support.h
+++ b/ui/gfx/x/xlib_support.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -9,6 +9,7 @@
#include <string>
#include "base/component_export.h"
+#include "base/memory/raw_ptr.h"
struct _XDisplay;
struct xcb_connection_t;
@@ -47,7 +48,7 @@
explicit XlibDisplay(const std::string& address);
- struct _XDisplay* display_ = nullptr;
+ raw_ptr<struct _XDisplay> display_ = nullptr;
};
// A temporary wrapper around an unowned Xlib display that adds behavior
@@ -71,7 +72,7 @@
friend class Connection;
- struct _XDisplay* display_;
+ raw_ptr<struct _XDisplay> display_;
XlibDisplayType type_;
};
diff --git a/ui/gfx/x/xlib_xcb.h b/ui/gfx/x/xlib_xcb.h
index 73d5649..f816403 100644
--- a/ui/gfx/x/xlib_xcb.h
+++ b/ui/gfx/x/xlib_xcb.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/xproto_internal.cc b/ui/gfx/x/xproto_internal.cc
index e0ffe7e..b4668cb 100644
--- a/ui/gfx/x/xproto_internal.cc
+++ b/ui/gfx/x/xproto_internal.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -14,7 +14,7 @@
: data_(reinterpret_cast<uint8_t*>(data)) {}
const uint8_t* MallocedRefCountedMemory::front() const {
- return data_;
+ return data_.get();
}
size_t MallocedRefCountedMemory::size() const {
@@ -23,9 +23,7 @@
return 0;
}
-MallocedRefCountedMemory::~MallocedRefCountedMemory() {
- free(data_);
-}
+MallocedRefCountedMemory::~MallocedRefCountedMemory() = default;
OffsetRefCountedMemory::OffsetRefCountedMemory(
scoped_refptr<base::RefCountedMemory> memory,
diff --git a/ui/gfx/x/xproto_internal.h b/ui/gfx/x/xproto_internal.h
index 6bf0f51..14332ea 100644
--- a/ui/gfx/x/xproto_internal.h
+++ b/ui/gfx/x/xproto_internal.h
@@ -1,10 +1,12 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_X_XPROTO_INTERNAL_H_
#define UI_GFX_X_XPROTO_INTERNAL_H_
+#include "base/memory/raw_ptr.h"
+
#ifndef IS_X11_IMPL
#error "This file should only be included by //ui/gfx/x:xprotos"
#endif
@@ -53,9 +55,16 @@
size_t size() const override;
private:
+ struct deleter {
+ void operator()(uint8_t* data) {
+ if (data) {
+ free(data);
+ }
+ }
+ };
~MallocedRefCountedMemory() override;
- uint8_t* const data_;
+ std::unique_ptr<uint8_t, deleter> data_;
};
// Wraps another RefCountedMemory, giving a view into it. Similar to
diff --git a/ui/gfx/x/xproto_types.cc b/ui/gfx/x/xproto_types.cc
index 5546cd8..5cdc104 100644
--- a/ui/gfx/x/xproto_types.cc
+++ b/ui/gfx/x/xproto_types.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/xproto_types.h b/ui/gfx/x/xproto_types.h
index e670fce..ab17f91 100644
--- a/ui/gfx/x/xproto_types.h
+++ b/ui/gfx/x/xproto_types.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,10 +8,11 @@
#include <cstdint>
#include <memory>
-#include "base/bind.h"
-#include "base/callback.h"
#include "base/component_export.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
#include "base/memory/free_deleter.h"
+#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/scoped_refptr.h"
@@ -49,7 +50,7 @@
scoped_refptr<base::RefCountedMemory> data;
size_t offset = 0;
- const int* fds = nullptr;
+ raw_ptr<const int, AllowPtrArithmetic> fds = nullptr;
};
// Wraps data to write to the connection.
diff --git a/ui/gfx/x/xproto_util.cc b/ui/gfx/x/xproto_util.cc
index 6662b12..5d3fd95 100644
--- a/ui/gfx/x/xproto_util.cc
+++ b/ui/gfx/x/xproto_util.cc
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
diff --git a/ui/gfx/x/xproto_util.h b/ui/gfx/x/xproto_util.h
index 60b1a35..560afc6 100644
--- a/ui/gfx/x/xproto_util.h
+++ b/ui/gfx/x/xproto_util.h
@@ -1,4 +1,4 @@
-// Copyright 2020 The Chromium Authors. All rights reserved.
+// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -8,6 +8,7 @@
#include <cstdint>
#include "base/component_export.h"
+#include "base/ranges/algorithm.h"
#include "ui/gfx/x/connection.h"
#include "ui/gfx/x/future.h"
#include "ui/gfx/x/xproto.h"
@@ -29,7 +30,7 @@
memcpy(event_bytes.data(), first_buffer->data(), first_buffer->size());
SendEventRequest send_event{false, target, mask};
- std::copy(event_bytes.begin(), event_bytes.end(), send_event.event.begin());
+ base::ranges::copy(event_bytes, send_event.event.begin());
return connection->SendEvent(send_event);
}
@@ -62,7 +63,8 @@
DCHECK_EQ(response->format / CHAR_BIT * response->value_len,
response->value->size());
value->resize(response->value_len);
- memcpy(value->data(), response->value->data(), response->value->size());
+ if (response->value_len > 0)
+ memcpy(value->data(), response->value->data(), response->value->size());
if (out_type)
*out_type = response->type;
return true;
@@ -90,7 +92,8 @@
Connection* connection = Connection::Get()) {
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4, "");
std::vector<uint8_t> data(sizeof(T) * values.size());
- memcpy(data.data(), values.data(), sizeof(T) * values.size());
+ if (values.size() > 0)
+ memcpy(data.data(), values.data(), sizeof(T) * values.size());
return connection->ChangeProperty(
ChangePropertyRequest{.window = static_cast<Window>(window),
.property = name,