summaryrefslogtreecommitdiffstats
path: root/chromium/ui/gfx
diff options
context:
space:
mode:
authorJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-08 14:30:41 +0200
committerJocelyn Turcotte <jocelyn.turcotte@digia.com>2014-08-12 13:49:54 +0200
commitab0a50979b9eb4dfa3320eff7e187e41efedf7a9 (patch)
tree498dfb8a97ff3361a9f7486863a52bb4e26bb898 /chromium/ui/gfx
parent4ce69f7403811819800e7c5ae1318b2647e778d1 (diff)
Update Chromium to beta version 37.0.2062.68
Change-Id: I188e3b5aff1bec75566014291b654eb19f5bc8ca Reviewed-by: Andras Becsi <andras.becsi@digia.com>
Diffstat (limited to 'chromium/ui/gfx')
-rw-r--r--chromium/ui/gfx/BUILD.gn445
-rw-r--r--chromium/ui/gfx/DEPS4
-rw-r--r--chromium/ui/gfx/OWNERS9
-rw-r--r--chromium/ui/gfx/android/OWNERS4
-rw-r--r--chromium/ui/gfx/android/bitmap_config_list.h15
-rw-r--r--chromium/ui/gfx/android/device_display_info.cc12
-rw-r--r--chromium/ui/gfx/android/device_display_info.h17
-rw-r--r--chromium/ui/gfx/android/java_bitmap.cc99
-rw-r--r--chromium/ui/gfx/android/java_bitmap.h40
-rw-r--r--chromium/ui/gfx/android/scroller.cc439
-rw-r--r--chromium/ui/gfx/android/scroller.h148
-rw-r--r--chromium/ui/gfx/android/scroller_unittest.cc167
-rw-r--r--chromium/ui/gfx/android/shared_device_display_info.cc57
-rw-r--r--chromium/ui/gfx/android/shared_device_display_info.h17
-rw-r--r--chromium/ui/gfx/android/view_configuration.cc196
-rw-r--r--chromium/ui/gfx/android/view_configuration.h8
-rw-r--r--chromium/ui/gfx/animation/animation.cc3
-rw-r--r--chromium/ui/gfx/animation/animation_delegate.h5
-rw-r--r--chromium/ui/gfx/animation/tween.cc10
-rw-r--r--chromium/ui/gfx/animation/tween.h25
-rw-r--r--chromium/ui/gfx/animation/tween_unittest.cc9
-rw-r--r--chromium/ui/gfx/blit.cc21
-rw-r--r--chromium/ui/gfx/box_f.h157
-rw-r--r--chromium/ui/gfx/canvas.cc301
-rw-r--r--chromium/ui/gfx/canvas.h145
-rw-r--r--chromium/ui/gfx/canvas_paint_gtk.cc107
-rw-r--r--chromium/ui/gfx/canvas_paint_gtk.h102
-rw-r--r--chromium/ui/gfx/canvas_skia.cc99
-rw-r--r--chromium/ui/gfx/canvas_skia_paint.h4
-rw-r--r--chromium/ui/gfx/canvas_unittest.cc16
-rw-r--r--chromium/ui/gfx/codec/png_codec.cc100
-rw-r--r--chromium/ui/gfx/codec/png_codec.h21
-rw-r--r--chromium/ui/gfx/codec/png_codec_unittest.cc51
-rw-r--r--chromium/ui/gfx/color_analysis.cc74
-rw-r--r--chromium/ui/gfx/color_analysis.h48
-rw-r--r--chromium/ui/gfx/color_analysis_unittest.cc140
-rw-r--r--chromium/ui/gfx/color_profile.cc7
-rw-r--r--chromium/ui/gfx/color_profile.h15
-rw-r--r--chromium/ui/gfx/color_profile_mac.cc27
-rw-r--r--chromium/ui/gfx/color_profile_mac.mm32
-rw-r--r--chromium/ui/gfx/color_profile_win.cc98
-rw-r--r--chromium/ui/gfx/color_profile_win_unittest.cc32
-rw-r--r--chromium/ui/gfx/color_utils.cc32
-rw-r--r--chromium/ui/gfx/color_utils.h14
-rw-r--r--chromium/ui/gfx/color_utils_unittest.cc75
-rw-r--r--chromium/ui/gfx/display.cc45
-rw-r--r--chromium/ui/gfx/display.h2
-rw-r--r--chromium/ui/gfx/display_observer.h16
-rw-r--r--chromium/ui/gfx/font.cc16
-rw-r--r--chromium/ui/gfx/font.h20
-rw-r--r--chromium/ui/gfx/font_fallback_win.cc13
-rw-r--r--chromium/ui/gfx/font_list.cc267
-rw-r--r--chromium/ui/gfx/font_list.h97
-rw-r--r--chromium/ui/gfx/font_list_impl.cc248
-rw-r--r--chromium/ui/gfx/font_list_impl.h123
-rw-r--r--chromium/ui/gfx/font_list_unittest.cc112
-rw-r--r--chromium/ui/gfx/font_render_params_linux.cc81
-rw-r--r--chromium/ui/gfx/font_smoothing_win.cc2
-rw-r--r--chromium/ui/gfx/font_unittest.cc46
-rw-r--r--chromium/ui/gfx/gdi_util.cc4
-rw-r--r--chromium/ui/gfx/gdk_compat.h27
-rw-r--r--chromium/ui/gfx/geometry/BUILD.gn62
-rw-r--r--chromium/ui/gfx/geometry/box_f.cc (renamed from chromium/ui/gfx/box_f.cc)2
-rw-r--r--chromium/ui/gfx/geometry/box_f.h160
-rw-r--r--chromium/ui/gfx/geometry/box_unittest.cc (renamed from chromium/ui/gfx/box_unittest.cc)2
-rw-r--r--chromium/ui/gfx/geometry/cubic_bezier.cc128
-rw-r--r--chromium/ui/gfx/geometry/cubic_bezier.h36
-rw-r--r--chromium/ui/gfx/geometry/cubic_bezier_unittest.cc140
-rw-r--r--chromium/ui/gfx/geometry/insets.cc (renamed from chromium/ui/gfx/insets.cc)15
-rw-r--r--chromium/ui/gfx/geometry/insets.h50
-rw-r--r--chromium/ui/gfx/geometry/insets_base.h (renamed from chromium/ui/gfx/insets_base.h)6
-rw-r--r--chromium/ui/gfx/geometry/insets_f.cc (renamed from chromium/ui/gfx/insets_f.cc)2
-rw-r--r--chromium/ui/gfx/geometry/insets_f.h33
-rw-r--r--chromium/ui/gfx/geometry/insets_unittest.cc (renamed from chromium/ui/gfx/insets_unittest.cc)2
-rw-r--r--chromium/ui/gfx/geometry/matrix3_f.cc (renamed from chromium/ui/gfx/matrix3_f.cc)2
-rw-r--r--chromium/ui/gfx/geometry/matrix3_f.h108
-rw-r--r--chromium/ui/gfx/geometry/matrix3_unittest.cc (renamed from chromium/ui/gfx/matrix3_unittest.cc)2
-rw-r--r--chromium/ui/gfx/geometry/point.cc (renamed from chromium/ui/gfx/point.cc)2
-rw-r--r--chromium/ui/gfx/geometry/point.h90
-rw-r--r--chromium/ui/gfx/geometry/point3_f.cc (renamed from chromium/ui/gfx/point3_f.cc)2
-rw-r--r--chromium/ui/gfx/geometry/point3_f.h120
-rw-r--r--chromium/ui/gfx/geometry/point3_unittest.cc (renamed from chromium/ui/gfx/point3_unittest.cc)3
-rw-r--r--chromium/ui/gfx/geometry/point_base.h (renamed from chromium/ui/gfx/point_base.h)6
-rw-r--r--chromium/ui/gfx/geometry/point_conversions.cc (renamed from chromium/ui/gfx/point_conversions.cc)4
-rw-r--r--chromium/ui/gfx/geometry/point_conversions.h24
-rw-r--r--chromium/ui/gfx/geometry/point_f.cc (renamed from chromium/ui/gfx/point_f.cc)2
-rw-r--r--chromium/ui/gfx/geometry/point_f.h75
-rw-r--r--chromium/ui/gfx/geometry/point_unittest.cc (renamed from chromium/ui/gfx/point_unittest.cc)9
-rw-r--r--chromium/ui/gfx/geometry/quad_f.cc (renamed from chromium/ui/gfx/quad_f.cc)32
-rw-r--r--chromium/ui/gfx/geometry/quad_f.h109
-rw-r--r--chromium/ui/gfx/geometry/quad_unittest.cc (renamed from chromium/ui/gfx/quad_unittest.cc)5
-rw-r--r--chromium/ui/gfx/geometry/r_tree.h182
-rw-r--r--chromium/ui/gfx/geometry/r_tree_base.cc658
-rw-r--r--chromium/ui/gfx/geometry/r_tree_base.h309
-rw-r--r--chromium/ui/gfx/geometry/r_tree_unittest.cc1025
-rw-r--r--chromium/ui/gfx/geometry/rect.cc (renamed from chromium/ui/gfx/rect.cc)19
-rw-r--r--chromium/ui/gfx/geometry/rect.h139
-rw-r--r--chromium/ui/gfx/geometry/rect_base.h (renamed from chromium/ui/gfx/rect_base.h)6
-rw-r--r--chromium/ui/gfx/geometry/rect_base_impl.h (renamed from chromium/ui/gfx/rect_base_impl.h)3
-rw-r--r--chromium/ui/gfx/geometry/rect_conversions.cc (renamed from chromium/ui/gfx/rect_conversions.cc)4
-rw-r--r--chromium/ui/gfx/geometry/rect_conversions.h36
-rw-r--r--chromium/ui/gfx/geometry/rect_f.cc (renamed from chromium/ui/gfx/rect_f.cc)8
-rw-r--r--chromium/ui/gfx/geometry/rect_f.h113
-rw-r--r--chromium/ui/gfx/geometry/rect_unittest.cc (renamed from chromium/ui/gfx/rect_unittest.cc)27
-rw-r--r--chromium/ui/gfx/geometry/safe_integer_conversions.h54
-rw-r--r--chromium/ui/gfx/geometry/safe_integer_conversions_unittest.cc (renamed from chromium/ui/gfx/safe_integer_conversions_unittest.cc)2
-rw-r--r--chromium/ui/gfx/geometry/size.cc (renamed from chromium/ui/gfx/size.cc)2
-rw-r--r--chromium/ui/gfx/geometry/size.h67
-rw-r--r--chromium/ui/gfx/geometry/size_base.h (renamed from chromium/ui/gfx/size_base.h)6
-rw-r--r--chromium/ui/gfx/geometry/size_conversions.cc (renamed from chromium/ui/gfx/size_conversions.cc)4
-rw-r--r--chromium/ui/gfx/geometry/size_conversions.h24
-rw-r--r--chromium/ui/gfx/geometry/size_f.cc (renamed from chromium/ui/gfx/size_f.cc)2
-rw-r--r--chromium/ui/gfx/geometry/size_f.h54
-rw-r--r--chromium/ui/gfx/geometry/size_unittest.cc (renamed from chromium/ui/gfx/size_unittest.cc)9
-rw-r--r--chromium/ui/gfx/geometry/vector2d.cc (renamed from chromium/ui/gfx/vector2d.cc)2
-rw-r--r--chromium/ui/gfx/geometry/vector2d.h91
-rw-r--r--chromium/ui/gfx/geometry/vector2d_conversions.cc (renamed from chromium/ui/gfx/vector2d_conversions.cc)4
-rw-r--r--chromium/ui/gfx/geometry/vector2d_conversions.h24
-rw-r--r--chromium/ui/gfx/geometry/vector2d_f.cc (renamed from chromium/ui/gfx/vector2d_f.cc)2
-rw-r--r--chromium/ui/gfx/geometry/vector2d_f.h112
-rw-r--r--chromium/ui/gfx/geometry/vector2d_unittest.cc (renamed from chromium/ui/gfx/vector2d_unittest.cc)4
-rw-r--r--chromium/ui/gfx/geometry/vector3d_f.cc (renamed from chromium/ui/gfx/vector3d_f.cc)2
-rw-r--r--chromium/ui/gfx/geometry/vector3d_f.h124
-rw-r--r--chromium/ui/gfx/geometry/vector3d_unittest.cc (renamed from chromium/ui/gfx/vector3d_unittest.cc)2
-rw-r--r--chromium/ui/gfx/gfx.gyp259
-rw-r--r--chromium/ui/gfx/gfx_tests.gyp146
-rw-r--r--chromium/ui/gfx/gpu_memory_buffer.cc14
-rw-r--r--chromium/ui/gfx/gpu_memory_buffer.h76
-rw-r--r--chromium/ui/gfx/gtk_compat.h97
-rw-r--r--chromium/ui/gfx/gtk_native_view_id_manager.cc254
-rw-r--r--chromium/ui/gfx/gtk_native_view_id_manager.h138
-rw-r--r--chromium/ui/gfx/gtk_preserve_window.cc264
-rw-r--r--chromium/ui/gfx/gtk_preserve_window.h74
-rw-r--r--chromium/ui/gfx/gtk_util.cc190
-rw-r--r--chromium/ui/gfx/gtk_util.h52
-rw-r--r--chromium/ui/gfx/icon_util.cc31
-rw-r--r--chromium/ui/gfx/icon_util_unittest.cc34
-rw-r--r--chromium/ui/gfx/icon_util_unittests.icobin0 -> 53740 bytes
-rw-r--r--chromium/ui/gfx/icon_util_unittests.rc36
-rw-r--r--chromium/ui/gfx/icon_util_unittests_resource.h5
-rw-r--r--chromium/ui/gfx/image/OWNERS2
-rw-r--r--chromium/ui/gfx/image/cairo_cached_surface.cc109
-rw-r--r--chromium/ui/gfx/image/cairo_cached_surface.h84
-rw-r--r--chromium/ui/gfx/image/image.cc393
-rw-r--r--chromium/ui/gfx/image/image.h24
-rw-r--r--chromium/ui/gfx/image/image_skia.cc94
-rw-r--r--chromium/ui/gfx/image/image_skia.h4
-rw-r--r--chromium/ui/gfx/image/image_skia_rep.cc19
-rw-r--r--chromium/ui/gfx/image/image_skia_rep.h16
-rw-r--r--chromium/ui/gfx/image/image_skia_unittest.cc185
-rw-r--r--chromium/ui/gfx/image/image_skia_util_mac.h4
-rw-r--r--chromium/ui/gfx/image/image_skia_util_mac.mm6
-rw-r--r--chromium/ui/gfx/image/image_unittest.cc53
-rw-r--r--chromium/ui/gfx/image/image_unittest_util.cc31
-rw-r--r--chromium/ui/gfx/image/image_unittest_util.h2
-rw-r--r--chromium/ui/gfx/image/image_util.cc57
-rw-r--r--chromium/ui/gfx/image/image_util.h17
-rw-r--r--chromium/ui/gfx/image/image_util_unittest.cc78
-rw-r--r--chromium/ui/gfx/insets.h51
-rw-r--r--chromium/ui/gfx/insets_f.h32
-rw-r--r--chromium/ui/gfx/linux_font_delegate.cc23
-rw-r--r--chromium/ui/gfx/linux_font_delegate.h49
-rw-r--r--chromium/ui/gfx/matrix3_f.h107
-rw-r--r--chromium/ui/gfx/native_widget_types.h80
-rw-r--r--chromium/ui/gfx/nine_image_painter.cc157
-rw-r--r--chromium/ui/gfx/nine_image_painter.h42
-rw-r--r--chromium/ui/gfx/overlay_transform.h24
-rw-r--r--chromium/ui/gfx/ozone/OWNERS1
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_skbitmap.cc208
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_skbitmap.h57
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_surface.cc113
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_surface.h168
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_surface_factory.cc317
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_surface_factory.h75
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_surface_factory_unittest.cc292
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_surface_unittest.cc212
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_vsync_provider.cc32
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_vsync_provider.h29
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_wrapper.cc93
-rw-r--r--chromium/ui/gfx/ozone/dri/dri_wrapper.h86
-rw-r--r--chromium/ui/gfx/ozone/dri/hardware_display_controller.cc129
-rw-r--r--chromium/ui/gfx/ozone/dri/hardware_display_controller.h190
-rw-r--r--chromium/ui/gfx/ozone/dri/hardware_display_controller_unittest.cc301
-rw-r--r--chromium/ui/gfx/ozone/impl/file_surface_factory.cc96
-rw-r--r--chromium/ui/gfx/ozone/impl/file_surface_factory.h49
-rw-r--r--chromium/ui/gfx/ozone/surface_factory_ozone.cc92
-rw-r--r--chromium/ui/gfx/ozone/surface_factory_ozone.h147
-rw-r--r--chromium/ui/gfx/pango_util.cc14
-rw-r--r--chromium/ui/gfx/path.h2
-rw-r--r--chromium/ui/gfx/path_gtk.cc55
-rw-r--r--chromium/ui/gfx/path_win.cc4
-rw-r--r--chromium/ui/gfx/path_x11.cc6
-rw-r--r--chromium/ui/gfx/path_x11.h5
-rw-r--r--chromium/ui/gfx/platform_font.h7
-rw-r--r--chromium/ui/gfx/platform_font_ios.h2
-rw-r--r--chromium/ui/gfx/platform_font_ios.mm9
-rw-r--r--chromium/ui/gfx/platform_font_mac.h2
-rw-r--r--chromium/ui/gfx/platform_font_mac.mm9
-rw-r--r--chromium/ui/gfx/platform_font_mac_unittest.mm8
-rw-r--r--chromium/ui/gfx/platform_font_pango.cc56
-rw-r--r--chromium/ui/gfx/platform_font_pango.h3
-rw-r--r--chromium/ui/gfx/platform_font_win.cc17
-rw-r--r--chromium/ui/gfx/platform_font_win.h2
-rw-r--r--chromium/ui/gfx/platform_font_win_unittest.cc8
-rw-r--r--chromium/ui/gfx/point.h89
-rw-r--r--chromium/ui/gfx/point3_f.h119
-rw-r--r--chromium/ui/gfx/point_conversions.h23
-rw-r--r--chromium/ui/gfx/point_f.h74
-rw-r--r--chromium/ui/gfx/quad_f.h108
-rw-r--r--chromium/ui/gfx/rect.h144
-rw-r--r--chromium/ui/gfx/rect_conversions.h35
-rw-r--r--chromium/ui/gfx/rect_f.h112
-rw-r--r--chromium/ui/gfx/render_text.cc395
-rw-r--r--chromium/ui/gfx/render_text.h132
-rw-r--r--chromium/ui/gfx/render_text_harfbuzz.cc1010
-rw-r--r--chromium/ui/gfx/render_text_harfbuzz.h130
-rw-r--r--chromium/ui/gfx/render_text_mac.cc22
-rw-r--r--chromium/ui/gfx/render_text_mac.h2
-rw-r--r--chromium/ui/gfx/render_text_ozone.cc2
-rw-r--r--chromium/ui/gfx/render_text_pango.cc56
-rw-r--r--chromium/ui/gfx/render_text_pango.h2
-rw-r--r--chromium/ui/gfx/render_text_unittest.cc336
-rw-r--r--chromium/ui/gfx/render_text_win.cc95
-rw-r--r--chromium/ui/gfx/render_text_win.h2
-rw-r--r--chromium/ui/gfx/safe_integer_conversions.h53
-rw-r--r--chromium/ui/gfx/scoped_gobject.h34
-rw-r--r--chromium/ui/gfx/screen_android.cc1
-rw-r--r--chromium/ui/gfx/screen_gtk.cc210
-rw-r--r--chromium/ui/gfx/screen_ios.mm3
-rw-r--r--chromium/ui/gfx/screen_mac.mm7
-rw-r--r--chromium/ui/gfx/screen_win.cc33
-rw-r--r--chromium/ui/gfx/selection_model.h11
-rw-r--r--chromium/ui/gfx/size.h66
-rw-r--r--chromium/ui/gfx/size_conversions.h23
-rw-r--r--chromium/ui/gfx/size_f.h53
-rw-r--r--chromium/ui/gfx/skbitmap_operations.cc78
-rw-r--r--chromium/ui/gfx/skia_util.cc43
-rw-r--r--chromium/ui/gfx/skia_util.h7
-rw-r--r--chromium/ui/gfx/skia_utils_gtk.cc32
-rw-r--r--chromium/ui/gfx/skia_utils_gtk.h23
-rw-r--r--chromium/ui/gfx/skrect_conversion_unittest.cc26
-rw-r--r--chromium/ui/gfx/switches.cc13
-rw-r--r--chromium/ui/gfx/switches.h4
-rw-r--r--chromium/ui/gfx/sys_color_change_listener.cc3
-rw-r--r--chromium/ui/gfx/text_constants.h41
-rw-r--r--chromium/ui/gfx/text_elider.cc526
-rw-r--r--chromium/ui/gfx/text_elider.h128
-rw-r--r--chromium/ui/gfx/text_elider_unittest.cc481
-rw-r--r--chromium/ui/gfx/text_utils_unittest.cc31
-rw-r--r--chromium/ui/gfx/transform.h8
-rw-r--r--chromium/ui/gfx/utf16_indexing_unittest.cc5
-rw-r--r--chromium/ui/gfx/vector2d.h90
-rw-r--r--chromium/ui/gfx/vector2d_conversions.h23
-rw-r--r--chromium/ui/gfx/vector2d_f.h111
-rw-r--r--chromium/ui/gfx/vector3d_f.h123
-rw-r--r--chromium/ui/gfx/win/dpi.cc159
-rw-r--r--chromium/ui/gfx/win/dpi.h27
-rw-r--r--chromium/ui/gfx/win/hwnd_util.cc19
-rw-r--r--chromium/ui/gfx/win/hwnd_util.h4
-rw-r--r--chromium/ui/gfx/win/msg_util.h2283
-rw-r--r--chromium/ui/gfx/win/singleton_hwnd.cc3
-rw-r--r--chromium/ui/gfx/win/window_impl.cc10
-rw-r--r--chromium/ui/gfx/win/window_impl.h6
-rw-r--r--chromium/ui/gfx/x/BUILD.gn32
-rw-r--r--chromium/ui/gfx/x/gfx_x11.gyp38
-rw-r--r--chromium/ui/gfx/x/x11_atom_cache.cc11
-rw-r--r--chromium/ui/gfx/x/x11_atom_cache.h18
-rw-r--r--chromium/ui/gfx/x/x11_connection.cc17
-rw-r--r--chromium/ui/gfx/x/x11_connection.h18
-rw-r--r--chromium/ui/gfx/x/x11_error_tracker.cc45
-rw-r--r--chromium/ui/gfx/x/x11_error_tracker.h36
-rw-r--r--chromium/ui/gfx/x/x11_switches.cc15
-rw-r--r--chromium/ui/gfx/x/x11_switches.h18
-rw-r--r--chromium/ui/gfx/x/x11_types.cc17
-rw-r--r--chromium/ui/gfx/x/x11_types.h3
275 files changed, 13770 insertions, 9415 deletions
diff --git a/chromium/ui/gfx/BUILD.gn b/chromium/ui/gfx/BUILD.gn
new file mode 100644
index 00000000000..e2796a1b7ac
--- /dev/null
+++ b/chromium/ui/gfx/BUILD.gn
@@ -0,0 +1,445 @@
+# 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.
+
+import("//build/config/ui.gni")
+
+if (is_android) {
+ import("//build/config/android/config.gni")
+ import("//build/config/android/rules.gni")
+}
+if (use_ozone) {
+ import("//ui/ozone/ozone.gni")
+}
+
+# Several targets want to include this header file, and some of them are
+# child dependencies of "gfx". Therefore, we separate it out here so multiple
+# targets can all have a dependency for header checking purposes without
+# creating circular dependencies.
+source_set("gfx_export") {
+ sources = [
+ "gfx_export.h",
+ ]
+}
+
+component("gfx") {
+ sources = [
+ "android/device_display_info.cc",
+ "android/device_display_info.h",
+ "android/gfx_jni_registrar.cc",
+ "android/gfx_jni_registrar.h",
+ "android/java_bitmap.cc",
+ "android/java_bitmap.h",
+ "android/scroller.cc",
+ "android/scroller.h",
+ "android/shared_device_display_info.cc",
+ "android/shared_device_display_info.h",
+ "android/view_configuration.cc",
+ "android/view_configuration.h",
+ "animation/animation.cc",
+ "animation/animation.h",
+ "animation/animation_container.cc",
+ "animation/animation_container.h",
+ "animation/animation_container_element.h",
+ "animation/animation_container_observer.h",
+ "animation/animation_delegate.h",
+ "animation/linear_animation.cc",
+ "animation/linear_animation.h",
+ "animation/multi_animation.cc",
+ "animation/multi_animation.h",
+ "animation/slide_animation.cc",
+ "animation/slide_animation.h",
+ "animation/throb_animation.cc",
+ "animation/throb_animation.h",
+ "animation/tween.cc",
+ "animation/tween.h",
+ "blit.cc",
+ "blit.h",
+ "break_list.h",
+ "canvas.cc",
+ "canvas.h",
+ "canvas_android.cc",
+ "canvas_paint_mac.h",
+ "canvas_paint_mac.mm",
+ "canvas_paint_win.cc",
+ "canvas_paint_win.h",
+ "canvas_skia.cc",
+ "canvas_skia_paint.h",
+ "codec/jpeg_codec.cc",
+ "codec/jpeg_codec.h",
+ "codec/png_codec.cc",
+ "codec/png_codec.h",
+ "color_analysis.cc",
+ "color_analysis.h",
+ "color_profile.cc",
+ "color_profile.h",
+ "color_profile_mac.mm",
+ "color_profile_win.cc",
+ "color_utils.cc",
+ "color_utils.h",
+ "display.cc",
+ "display.h",
+ "display_observer.cc",
+ "display_observer.h",
+ "favicon_size.cc",
+ "favicon_size.h",
+ "font.cc",
+ "font.h",
+ "font_fallback_win.cc",
+ "font_fallback_win.h",
+ "font_list.cc",
+ "font_list.h",
+ "font_list_impl.cc",
+ "font_list_impl.h",
+ "font_render_params_android.cc",
+ "font_render_params_linux.cc",
+ "font_render_params_linux.h",
+ "font_smoothing_win.cc",
+ "font_smoothing_win.h",
+ "frame_time.h",
+ "gdi_util.cc",
+ "gdi_util.h",
+ "gfx_paths.cc",
+ "gfx_paths.h",
+ "gpu_memory_buffer.cc",
+ "gpu_memory_buffer.h",
+ "icon_util.cc",
+ "icon_util.h",
+ "image/canvas_image_source.cc",
+ "image/canvas_image_source.h",
+ "image/image.cc",
+ "image/image.h",
+ "image/image_family.cc",
+ "image/image_family.h",
+ "image/image_ios.mm",
+ "image/image_mac.mm",
+ "image/image_png_rep.cc",
+ "image/image_png_rep.h",
+ "image/image_skia.cc",
+ "image/image_skia.h",
+ "image/image_skia_operations.cc",
+ "image/image_skia_operations.h",
+ "image/image_skia_rep.cc",
+ "image/image_skia_rep.h",
+ "image/image_skia_source.h",
+ "image/image_skia_util_ios.h",
+ "image/image_skia_util_ios.mm",
+ "image/image_skia_util_mac.h",
+ "image/image_skia_util_mac.mm",
+ "image/image_util.cc",
+ "image/image_util.h",
+ "image/image_util_ios.mm",
+ "interpolated_transform.cc",
+ "interpolated_transform.h",
+ "linux_font_delegate.cc",
+ "linux_font_delegate.h",
+ "mac/scoped_ns_disable_screen_updates.h",
+ "native_widget_types.h",
+ "nine_image_painter.cc",
+ "nine_image_painter.h",
+ "path.cc",
+ "path.h",
+ "path_aura.cc",
+ "path_win.cc",
+ "path_win.h",
+ "path_x11.cc",
+ "path_x11.h",
+ "platform_font.h",
+ "platform_font_android.cc",
+ "platform_font_ios.h",
+ "platform_font_ios.mm",
+ "platform_font_mac.h",
+ "platform_font_mac.mm",
+ "platform_font_win.cc",
+ "platform_font_win.h",
+ "range/range.cc",
+ "range/range.h",
+ "range/range_mac.mm",
+ "range/range_win.cc",
+ "scoped_canvas.h",
+ "scoped_cg_context_save_gstate_mac.h",
+ "scoped_ns_graphics_context_save_gstate_mac.h",
+ "scoped_ns_graphics_context_save_gstate_mac.mm",
+ "scoped_ui_graphics_push_context_ios.h",
+ "scoped_ui_graphics_push_context_ios.mm",
+ "screen.cc",
+ "screen.h",
+ "screen_android.cc",
+ "screen_aura.cc",
+ "screen_ios.mm",
+ "screen_mac.mm",
+ "screen_win.cc",
+ "screen_win.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",
+ "skia_util.cc",
+ "skia_util.h",
+ "switches.cc",
+ "switches.h",
+ "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",
+ "text_utils_android.cc",
+ "text_utils_ios.mm",
+ "transform.cc",
+ "transform.h",
+ "transform_util.cc",
+ "transform_util.h",
+ "ui_gfx_exports.cc",
+ "utf16_indexing.cc",
+ "utf16_indexing.h",
+ "vsync_provider.h",
+ "win/dpi.cc",
+ "win/dpi.h",
+ "win/hwnd_util.cc",
+ "win/hwnd_util.h",
+ "win/scoped_set_map_mode.h",
+ "win/singleton_hwnd.cc",
+ "win/singleton_hwnd.h",
+ "win/window_impl.cc",
+ "win/window_impl.h",
+ ]
+
+ defines = [ "GFX_IMPLEMENTATION" ]
+
+ deps = [
+ ":gfx_export",
+ "//base",
+ "//base:i18n",
+ "//base:base_static",
+ "//base/third_party/dynamic_annotations",
+ "//skia",
+ "//third_party/harfbuzz-ng",
+ "//third_party/icu:icui18n",
+ "//third_party/icu:icuuc",
+ "//third_party/libpng",
+ "//third_party/zlib",
+ "//ui/gfx/geometry",
+ ]
+
+ # Text rendering conditions (complicated so separated out).
+ if (is_android || is_ios) {
+ # We don't support RenderText on these platforms.
+ } else {
+ # These text rendering files are supported everywhere text rendering is.
+ sources += [
+ "render_text.cc",
+ "render_text.h",
+ "render_text_harfbuzz.cc",
+ "render_text_harfbuzz.h",
+ "text_utils_skia.cc",
+ ]
+ # These are the "native" rendering routines, only one should apply.
+ if (is_win) {
+ sources += [ "render_text_win.cc" ]
+ } else if (is_mac) {
+ sources += [ "render_text_mac.cc" ]
+ } else if (use_pango) {
+ sources += [ "render_text_pango.cc" ]
+ } else if (use_ozone) {
+ sources += [ "render_text_ozone.cc" ]
+ }
+ }
+
+ # iOS.
+ if (is_ios) {
+ sources -= [
+ "codec/jpeg_codec.cc",
+ "codec/jpeg_codec.h",
+ ]
+ } else {
+ deps += [ "//third_party:jpeg" ]
+ }
+
+ # Android.
+ if (is_android) {
+ sources -= [
+ "animation/throb_animation.cc",
+ "canvas_skia.cc",
+ "display_observer.cc",
+ "selection_model.cc",
+ ]
+
+ if (use_aura) {
+ sources -= [ "screen_android.cc" ]
+ } else {
+ sources -= [ "path.cc" ]
+ }
+
+ # TODO(GYP) re-enable when base_java exists.
+ #if (!is_android_webview_build) {
+ # deps += [ "//base:base_java" ]
+ #}
+
+ deps += [ ":gfx_jni_headers" ]
+ libs = [
+ "android",
+ "jnigraphics",
+ ]
+ }
+
+ # Windows.
+ if (is_win) {
+ cflags = [
+ "/wd4267", # TODO(jschuh): C4267: http://crbug.com/167187 size_t -> int.
+ "/wd4324", # Structure was padded due to __declspec(align()), which is
+ # uninteresting.
+ ]
+ } else {
+ sources -= [
+ "gdi_util.cc",
+ "gdi_util.h",
+ "icon_util.cc",
+ "icon_util.h",
+ ]
+ }
+
+ # Linux.
+ if (is_linux) {
+ configs += [ "//build/config/linux:fontconfig" ]
+ }
+
+ # Ozone stuff.
+ if (use_ozone) {
+ sources += [
+ "platform_font_ozone.cc",
+ "ozone/impl/file_surface_factory.cc",
+ "ozone/impl/file_surface_factory.h",
+ "ozone/surface_factory_ozone.cc",
+ "ozone/surface_factory_ozone.h",
+ "ozone/surface_ozone.h",
+ "ozone/overlay_candidates_ozone.cc",
+ "ozone/overlay_candidates_ozone.h",
+ ]
+ }
+
+ if (!use_aura) {
+ sources -= [
+ "nine_image_painter.cc",
+ "nine_image_painter.h",
+ "path_aura.cc",
+ "screen_aura.cc",
+ ]
+ }
+
+ if (use_x11) {
+ deps += [
+ ":gfx_x11",
+ ]
+ } else {
+ sources -= [
+ "path_x11.cc",
+ ]
+ }
+
+ if (use_pango) {
+ sources += [
+ "pango_util.cc",
+ "pango_util.h",
+ "platform_font_pango.cc",
+ "platform_font_pango.h",
+ ]
+ configs += [ "//build/config/linux:pangocairo" ]
+ }
+}
+
+# Looking for gfx_geometry? It's //ui/gfx/geometry:geometry
+
+source_set("gfx_test_support") {
+ sources = [
+ "test/gfx_util.cc",
+ "test/gfx_util.h",
+ "test/ui_cocoa_test_helper.h",
+ "test/ui_cocoa_test_helper.mm",
+ ]
+
+ deps = [
+ "//base",
+ "//base/test:test_support",
+ "//skia",
+ "//testing/gtest",
+ ]
+
+ if (is_ios) {
+ # The cocoa files don't apply to iOS.
+ sources -= [
+ "test/ui_cocoa_test_helper.h",
+ "test/ui_cocoa_test_helper.mm",
+ ]
+ }
+}
+
+test("gfx_unittests") {
+ sources = [
+ "geometry/box_unittest.cc",
+ "geometry/cubic_bezier_unittest.cc",
+ "geometry/insets_unittest.cc",
+ "geometry/matrix3_unittest.cc",
+ "geometry/point_unittest.cc",
+ "geometry/point3_unittest.cc",
+ "geometry/quad_unittest.cc",
+ "geometry/rect_unittest.cc",
+ "geometry/safe_integer_conversions_unittest.cc",
+ "geometry/size_unittest.cc",
+ "geometry/vector2d_unittest.cc",
+ "geometry/vector3d_unittest.cc",
+ "range/range_unittest.cc",
+ ]
+
+ deps = [
+ ":gfx",
+ "//base",
+ "//base/test:run_all_unittests",
+ "//base/test:run_all_unittests",
+ "//testing/gtest",
+ "//ui/gfx/geometry",
+ ]
+}
+
+if (is_android) {
+ generate_jni("gfx_jni_headers") {
+ sources = [
+ "../android/java/src/org/chromium/ui/gfx/BitmapHelper.java",
+ "../android/java/src/org/chromium/ui/gfx/DeviceDisplayInfo.java",
+ "../android/java/src/org/chromium/ui/gfx/ViewConfigurationHelper.java",
+ ]
+ jni_package = "gfx"
+ }
+}
+
+if (use_x11) {
+ component("gfx_x11") {
+ sources = [
+ "x/x11_atom_cache.cc",
+ "x/x11_atom_cache.h",
+ "x/x11_connection.cc",
+ "x/x11_connection.h",
+ "x/x11_error_tracker.cc",
+ "x/x11_error_tracker.h",
+ "x/x11_switches.cc",
+ "x/x11_switches.h",
+ "x/x11_types.cc",
+ "x/x11_types.h",
+ ]
+
+ defines = [ "GFX_IMPLEMENTATION" ]
+ configs += [ "//build/config/linux:x11" ]
+
+ deps = [
+ ":gfx_export",
+ "//base"
+ ]
+ }
+}
diff --git a/chromium/ui/gfx/DEPS b/chromium/ui/gfx/DEPS
index 07a2ea9406f..758e42abb66 100644
--- a/chromium/ui/gfx/DEPS
+++ b/chromium/ui/gfx/DEPS
@@ -1,8 +1,6 @@
include_rules = [
"+base",
- "+net",
"+skia/ext",
- "+third_party/angle",
+ "+third_party/harfbuzz-ng",
"+third_party/skia",
- "+ui/test/ui_unittests_resource.h", # TODO(beng): remove
]
diff --git a/chromium/ui/gfx/OWNERS b/chromium/ui/gfx/OWNERS
index 563c600ea4d..dad6c9a8452 100644
--- a/chromium/ui/gfx/OWNERS
+++ b/chromium/ui/gfx/OWNERS
@@ -7,9 +7,6 @@ danakj@chromium.org
# RenderText and related classes.
msw@chromium.org
-# RenderText and related classes.
-xji@chromium.org
-
# Display and related classes.
per-file display*=oshima@chromium.org
per-file screen*=oshima@chromium.org
@@ -19,5 +16,11 @@ per-file transform*=shawnsingh@chromium.org
per-file transform*=vollick@chromium.org
per-file interpolated_transform*=vollick@chromium.org
+# GPU memory buffer interface.
+per-file gpu_memory_buffer*=reveman@chromium.org
+
+# R-Tree implementation.
+per-file r_tree*=luken@chromium.org
+
# If you're doing structural changes get a review from one of the OWNERS.
per-file *.gyp*=*
diff --git a/chromium/ui/gfx/android/OWNERS b/chromium/ui/gfx/android/OWNERS
index c87688f018a..316565b6ed3 100644
--- a/chromium/ui/gfx/android/OWNERS
+++ b/chromium/ui/gfx/android/OWNERS
@@ -1 +1,3 @@
-yfriedman@chromium.org
+aelias@chromium.org
+jdduke@chromium.org
+skyostil@chromium.org
diff --git a/chromium/ui/gfx/android/bitmap_config_list.h b/chromium/ui/gfx/android/bitmap_config_list.h
new file mode 100644
index 00000000000..9561168f3b3
--- /dev/null
+++ b/chromium/ui/gfx/android/bitmap_config_list.h
@@ -0,0 +1,15 @@
+// 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.
+
+// This file intentionally does not have header guards, it's included
+// inside a macro to generate enum values.
+
+#ifndef DEFINE_BITMAP_CONFIG
+#error "DEFINE_BITMAP_CONFIG should be defined before including this file"
+#endif
+DEFINE_BITMAP_CONFIG(FORMAT_NO_CONFIG, 0)
+DEFINE_BITMAP_CONFIG(FORMAT_ALPHA_8, 1)
+DEFINE_BITMAP_CONFIG(FORMAT_ARGB_4444, 2)
+DEFINE_BITMAP_CONFIG(FORMAT_ARGB_8888, 3)
+DEFINE_BITMAP_CONFIG(FORMAT_RGB_565, 4)
diff --git a/chromium/ui/gfx/android/device_display_info.cc b/chromium/ui/gfx/android/device_display_info.cc
index 2de8440e1d3..4d2c80c09d6 100644
--- a/chromium/ui/gfx/android/device_display_info.cc
+++ b/chromium/ui/gfx/android/device_display_info.cc
@@ -23,6 +23,14 @@ int DeviceDisplayInfo::GetDisplayWidth() {
return SharedDeviceDisplayInfo::GetInstance()->GetDisplayWidth();
}
+int DeviceDisplayInfo::GetPhysicalDisplayHeight() {
+ return SharedDeviceDisplayInfo::GetInstance()->GetPhysicalDisplayHeight();
+}
+
+int DeviceDisplayInfo::GetPhysicalDisplayWidth() {
+ return SharedDeviceDisplayInfo::GetInstance()->GetPhysicalDisplayWidth();
+}
+
int DeviceDisplayInfo::GetBitsPerPixel() {
return SharedDeviceDisplayInfo::GetInstance()->GetBitsPerPixel();
}
@@ -39,4 +47,8 @@ int DeviceDisplayInfo::GetSmallestDIPWidth() {
return SharedDeviceDisplayInfo::GetInstance()->GetSmallestDIPWidth();
}
+int DeviceDisplayInfo::GetRotationDegrees() {
+ return SharedDeviceDisplayInfo::GetInstance()->GetRotationDegrees();
+}
+
} // namespace gfx
diff --git a/chromium/ui/gfx/android/device_display_info.h b/chromium/ui/gfx/android/device_display_info.h
index 83968e9b51e..74e0ada4875 100644
--- a/chromium/ui/gfx/android/device_display_info.h
+++ b/chromium/ui/gfx/android/device_display_info.h
@@ -26,6 +26,18 @@ class GFX_EXPORT DeviceDisplayInfo {
// Returns display width in physical pixels.
int GetDisplayWidth();
+ // Returns real display height in physical pixels.
+ // This version does not subtract window decorations etc.
+ // WARNING: This is only supported on JB-MR1 (sdk >= 17). Either
+ // check the SDK-level, or check for '0' being returned.
+ int GetPhysicalDisplayHeight();
+
+ // Returns real display width in physical pixels.
+ // This version does not subtract window decorations etc.
+ // WARNING: This is only supported on JB-MR1 (sdk >= 17). Either
+ // check the SDK-level, or check for '0' being returned.
+ int GetPhysicalDisplayWidth();
+
// Returns number of bits per pixel.
int GetBitsPerPixel();
@@ -39,6 +51,11 @@ class GFX_EXPORT DeviceDisplayInfo {
// Smallest possible screen size in density-independent pixels.
int GetSmallestDIPWidth();
+ // Returns the display rotation angle from its natural orientation. Expected
+ // values are one of { 0, 90, 180, 270 }.
+ // See DeviceDispayInfo.java for more information.
+ int GetRotationDegrees();
+
private:
DISALLOW_COPY_AND_ASSIGN(DeviceDisplayInfo);
};
diff --git a/chromium/ui/gfx/android/java_bitmap.cc b/chromium/ui/gfx/android/java_bitmap.cc
index 2a1be65d215..a5b891a4af7 100644
--- a/chromium/ui/gfx/android/java_bitmap.cc
+++ b/chromium/ui/gfx/android/java_bitmap.cc
@@ -9,11 +9,10 @@
#include "base/android/jni_string.h"
#include "base/logging.h"
#include "jni/BitmapHelper_jni.h"
-#include "skia/ext/image_operations.h"
-#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/size.h"
using base::android::AttachCurrentThread;
+using base::android::ConvertUTF8ToJavaString;
namespace gfx {
@@ -42,17 +41,52 @@ bool JavaBitmap::RegisterJavaBitmap(JNIEnv* env) {
return RegisterNativesImpl(env);
}
-static ScopedJavaLocalRef<jobject> CreateJavaBitmap(const gfx::Size& size) {
- return Java_BitmapHelper_createBitmap(AttachCurrentThread(),
- size.width(), size.height());
+static int SkBitmapConfigToBitmapFormat(SkBitmap::Config bitmap_config) {
+ switch (bitmap_config) {
+ case SkBitmap::kA8_Config:
+ return BITMAP_FORMAT_ALPHA_8;
+ case SkBitmap::kARGB_4444_Config:
+ return BITMAP_FORMAT_ARGB_4444;
+ case SkBitmap::kARGB_8888_Config:
+ return BITMAP_FORMAT_ARGB_8888;
+ case SkBitmap::kRGB_565_Config:
+ return BITMAP_FORMAT_RGB_565;
+ case SkBitmap::kNo_Config:
+ default:
+ NOTREACHED();
+ return BITMAP_FORMAT_NO_CONFIG;
+ }
+}
+
+ScopedJavaLocalRef<jobject> CreateJavaBitmap(int width,
+ int height,
+ SkBitmap::Config bitmap_config) {
+ DCHECK_GT(width, 0);
+ DCHECK_GT(height, 0);
+ int java_bitmap_config = SkBitmapConfigToBitmapFormat(bitmap_config);
+ return Java_BitmapHelper_createBitmap(
+ AttachCurrentThread(), width, height, java_bitmap_config);
+}
+
+ScopedJavaLocalRef<jobject> CreateJavaBitmapFromAndroidResource(
+ const char* name,
+ gfx::Size size) {
+ DCHECK(name);
+ DCHECK(!size.IsEmpty());
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> jname(ConvertUTF8ToJavaString(env, name));
+ return Java_BitmapHelper_decodeDrawableResource(
+ env, jname.obj(), size.width(), size.height());
}
ScopedJavaLocalRef<jobject> ConvertToJavaBitmap(const SkBitmap* skbitmap) {
DCHECK(skbitmap);
- DCHECK_EQ(skbitmap->bytesPerPixel(), 4);
-
- ScopedJavaLocalRef<jobject> jbitmap =
- CreateJavaBitmap(gfx::Size(skbitmap->width(), skbitmap->height()));
+ DCHECK(!skbitmap->isNull());
+ SkBitmap::Config bitmap_config = skbitmap->config();
+ DCHECK((bitmap_config == SkBitmap::kRGB_565_Config) ||
+ (bitmap_config == SkBitmap::kARGB_8888_Config));
+ ScopedJavaLocalRef<jobject> jbitmap = CreateJavaBitmap(
+ skbitmap->width(), skbitmap->height(), bitmap_config);
SkAutoLockPixels src_lock(*skbitmap);
JavaBitmap dst_lock(jbitmap.obj());
void* src_pixels = skbitmap->getPixels();
@@ -62,8 +96,13 @@ ScopedJavaLocalRef<jobject> ConvertToJavaBitmap(const SkBitmap* skbitmap) {
return jbitmap;
}
-SkBitmap CreateSkBitmapFromJavaBitmap(JavaBitmap& jbitmap) {
- DCHECK_EQ(jbitmap.format(), ANDROID_BITMAP_FORMAT_RGBA_8888);
+SkBitmap CreateSkBitmapFromJavaBitmap(const JavaBitmap& jbitmap) {
+ // TODO(jdduke): Convert to DCHECK's when sufficient data has been capture for
+ // crbug.com/341406.
+ CHECK_EQ(jbitmap.format(), ANDROID_BITMAP_FORMAT_RGBA_8888);
+ CHECK(!jbitmap.size().IsEmpty());
+ CHECK_GT(jbitmap.stride(), 0U);
+ CHECK(jbitmap.pixels());
gfx::Size src_size = jbitmap.size();
@@ -72,30 +111,34 @@ SkBitmap CreateSkBitmapFromJavaBitmap(JavaBitmap& jbitmap) {
src_size.width(),
src_size.height(),
jbitmap.stride());
- skbitmap.allocPixels();
+ if (!skbitmap.allocPixels()) {
+ LOG(FATAL) << " Failed to allocate bitmap of size " << src_size.width()
+ << "x" << src_size.height() << " stride=" << jbitmap.stride();
+ }
SkAutoLockPixels dst_lock(skbitmap);
-
- void* src_pixels = jbitmap.pixels();
+ const void* src_pixels = jbitmap.pixels();
void* dst_pixels = skbitmap.getPixels();
-
memcpy(dst_pixels, src_pixels, skbitmap.getSize());
return skbitmap;
}
-SkBitmap CreateSkBitmapFromResource(const char* name, gfx::Size size) {
- DCHECK(!size.IsEmpty());
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jstring> jname(env, env->NewStringUTF(name));
- ScopedJavaLocalRef<jobject> jobj(Java_BitmapHelper_decodeDrawableResource(
- env, jname.obj(), size.width(), size.height()));
- if (jobj.is_null())
- return SkBitmap();
-
- JavaBitmap jbitmap(jobj.obj());
- SkBitmap bitmap = CreateSkBitmapFromJavaBitmap(jbitmap);
- return skia::ImageOperations::Resize(
- bitmap, skia::ImageOperations::RESIZE_BOX, size.width(), size.height());
+SkBitmap::Config ConvertToSkiaConfig(jobject bitmap_config) {
+ int jbitmap_config = Java_BitmapHelper_getBitmapFormatForConfig(
+ AttachCurrentThread(), bitmap_config);
+ switch (jbitmap_config) {
+ case BITMAP_FORMAT_ALPHA_8:
+ return SkBitmap::kA8_Config;
+ case BITMAP_FORMAT_ARGB_4444:
+ return SkBitmap::kARGB_4444_Config;
+ case BITMAP_FORMAT_ARGB_8888:
+ return SkBitmap::kARGB_8888_Config;
+ case BITMAP_FORMAT_RGB_565:
+ return SkBitmap::kRGB_565_Config;
+ case BITMAP_FORMAT_NO_CONFIG:
+ default:
+ return SkBitmap::kNo_Config;
+ }
}
} // namespace gfx
diff --git a/chromium/ui/gfx/android/java_bitmap.h b/chromium/ui/gfx/android/java_bitmap.h
index 9d1e4432cb7..44a17cade74 100644
--- a/chromium/ui/gfx/android/java_bitmap.h
+++ b/chromium/ui/gfx/android/java_bitmap.h
@@ -8,12 +8,20 @@
#include <jni.h>
#include "base/android/scoped_java_ref.h"
+#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/size.h"
-class SkBitmap;
-
namespace gfx {
+// Define Bitmap Config values like BITMAP_CONFIG_ARGB_8888 in a
+// way that ensures they're always the same than their Java counterpart.
+
+enum BitmapConfig {
+#define DEFINE_BITMAP_CONFIG(x, y) BITMAP_##x = y,
+#include "bitmap_config_list.h"
+#undef DEFINE_BITMAP_CONFIG
+};
+
// This class wraps a JNI AndroidBitmap object to make it easier to use. It
// handles locking and unlocking of the underlying pixels, along with wrapping
// various JNI methods.
@@ -23,6 +31,7 @@ class GFX_EXPORT JavaBitmap {
~JavaBitmap();
inline void* pixels() { return pixels_; }
+ inline const void* pixels() const { return pixels_; }
inline const gfx::Size& size() const { return size_; }
// Formats are in android/bitmap.h; e.g. ANDROID_BITMAP_FORMAT_RGBA_8888
inline int format() const { return format_; }
@@ -41,15 +50,32 @@ class GFX_EXPORT JavaBitmap {
DISALLOW_COPY_AND_ASSIGN(JavaBitmap);
};
+// Allocates a Java-backed bitmap (android.graphics.Bitmap) with the given
+// (non-empty!) size and configuration.
+GFX_EXPORT base::android::ScopedJavaLocalRef<jobject> CreateJavaBitmap(
+ int width,
+ int height,
+ SkBitmap::Config bitmap_config);
+
+// Loads a Java-backed bitmap (android.graphics.Bitmap) from the provided
+// drawable resource identifier (e.g., android:drawable/overscroll_glow). If the
+// resource loads successfully, it will be integrally scaled down, preserving
+// aspect ratio, to a size no smaller than |size|. Otherwise, null is returned.
+GFX_EXPORT base::android::ScopedJavaLocalRef<jobject>
+ CreateJavaBitmapFromAndroidResource(const char* name, gfx::Size size);
+
+// Converts |skbitmap| to a Java-backed bitmap (android.graphics.Bitmap).
+// Note: |skbitmap| is assumed to be non-null, non-empty and one of RGBA_8888 or
+// RGB_565 formats.
GFX_EXPORT base::android::ScopedJavaLocalRef<jobject> ConvertToJavaBitmap(
const SkBitmap* skbitmap);
-GFX_EXPORT SkBitmap CreateSkBitmapFromJavaBitmap(JavaBitmap& jbitmap);
+// Converts |bitmap| to an SkBitmap of the same size and format.
+// Note: |jbitmap| is assumed to be non-null, non-empty and of format RGBA_8888.
+GFX_EXPORT SkBitmap CreateSkBitmapFromJavaBitmap(const JavaBitmap& jbitmap);
-// If the resource loads successfully, it will be resized to |size|.
-// Note: If the source resource is smaller than |size|, quality may suffer.
-GFX_EXPORT SkBitmap CreateSkBitmapFromResource(const char* name,
- gfx::Size size);
+// Returns a Skia config value for the requested input java Bitmap.Config.
+GFX_EXPORT SkBitmap::Config ConvertToSkiaConfig(jobject bitmap_config);
} // namespace gfx
diff --git a/chromium/ui/gfx/android/scroller.cc b/chromium/ui/gfx/android/scroller.cc
new file mode 100644
index 00000000000..4a44741f52e
--- /dev/null
+++ b/chromium/ui/gfx/android/scroller.cc
@@ -0,0 +1,439 @@
+// 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/android/scroller.h"
+
+#include <cmath>
+
+#include "base/lazy_instance.h"
+
+namespace gfx {
+namespace {
+
+// Default scroll duration from android.widget.Scroller.
+const int kDefaultDurationMs = 250;
+
+// Default friction constant in android.view.ViewConfiguration.
+const float kDefaultFriction = 0.015f;
+
+// == std::log(0.78f) / std::log(0.9f)
+const float kDecelerationRate = 2.3582018f;
+
+// Tension lines cross at (kInflexion, 1).
+const float kInflexion = 0.35f;
+
+const float kEpsilon = 1e-5f;
+
+bool ApproxEquals(float a, float b) {
+ return std::abs(a - b) < kEpsilon;
+}
+
+struct ViscosityConstants {
+ ViscosityConstants()
+ : viscous_fluid_scale_(8.f), viscous_fluid_normalize_(1.f) {
+ viscous_fluid_normalize_ = 1.0f / ApplyViscosity(1.0f);
+ }
+
+ float ApplyViscosity(float x) {
+ x *= viscous_fluid_scale_;
+ if (x < 1.0f) {
+ x -= (1.0f - std::exp(-x));
+ } else {
+ float start = 0.36787944117f; // 1/e == exp(-1)
+ x = 1.0f - std::exp(1.0f - x);
+ x = start + x * (1.0f - start);
+ }
+ x *= viscous_fluid_normalize_;
+ return x;
+ }
+
+ private:
+ // This controls the intensity of the viscous fluid effect.
+ float viscous_fluid_scale_;
+ float viscous_fluid_normalize_;
+
+ DISALLOW_COPY_AND_ASSIGN(ViscosityConstants);
+};
+
+struct SplineConstants {
+ SplineConstants() {
+ const float kStartTension = 0.5f;
+ const float kEndTension = 1.0f;
+ const float kP1 = kStartTension * kInflexion;
+ const float kP2 = 1.0f - kEndTension * (1.0f - kInflexion);
+
+ float x_min = 0.0f;
+ float y_min = 0.0f;
+ for (int i = 0; i < NUM_SAMPLES; i++) {
+ const float alpha = static_cast<float>(i) / NUM_SAMPLES;
+
+ float x_max = 1.0f;
+ float x, tx, coef;
+ while (true) {
+ x = x_min + (x_max - x_min) / 2.0f;
+ coef = 3.0f * x * (1.0f - x);
+ tx = coef * ((1.0f - x) * kP1 + x * kP2) + x * x * x;
+ if (ApproxEquals(tx, alpha))
+ break;
+ if (tx > alpha)
+ x_max = x;
+ else
+ x_min = x;
+ }
+ spline_position_[i] = coef * ((1.0f - x) * kStartTension + x) + x * x * x;
+
+ float y_max = 1.0f;
+ float y, dy;
+ while (true) {
+ y = y_min + (y_max - y_min) / 2.0f;
+ coef = 3.0f * y * (1.0f - y);
+ dy = coef * ((1.0f - y) * kStartTension + y) + y * y * y;
+ if (ApproxEquals(dy, alpha))
+ break;
+ if (dy > alpha)
+ y_max = y;
+ else
+ y_min = y;
+ }
+ spline_time_[i] = coef * ((1.0f - y) * kP1 + y * kP2) + y * y * y;
+ }
+ spline_position_[NUM_SAMPLES] = spline_time_[NUM_SAMPLES] = 1.0f;
+ }
+
+ void CalculateCoefficients(float t,
+ float* distance_coef,
+ float* velocity_coef) {
+ *distance_coef = 1.f;
+ *velocity_coef = 0.f;
+ const int index = static_cast<int>(NUM_SAMPLES * t);
+ if (index < NUM_SAMPLES) {
+ const float t_inf = static_cast<float>(index) / NUM_SAMPLES;
+ const float t_sup = static_cast<float>(index + 1) / NUM_SAMPLES;
+ const float d_inf = spline_position_[index];
+ const float d_sup = spline_position_[index + 1];
+ *velocity_coef = (d_sup - d_inf) / (t_sup - t_inf);
+ *distance_coef = d_inf + (t - t_inf) * *velocity_coef;
+ }
+ }
+
+ private:
+ enum {
+ NUM_SAMPLES = 100
+ };
+
+ float spline_position_[NUM_SAMPLES + 1];
+ float spline_time_[NUM_SAMPLES + 1];
+
+ DISALLOW_COPY_AND_ASSIGN(SplineConstants);
+};
+
+float ComputeDeceleration(float friction) {
+ const float kGravityEarth = 9.80665f;
+ return kGravityEarth // g (m/s^2)
+ * 39.37f // inch/meter
+ * 160.f // pixels/inch
+ * friction;
+}
+
+template <typename T>
+int Signum(T t) {
+ return (T(0) < t) - (t < T(0));
+}
+
+template <typename T>
+T Clamped(T t, T a, T b) {
+ return t < a ? a : (t > b ? b : t);
+}
+
+// Leaky to allow access from the impl thread.
+base::LazyInstance<ViscosityConstants>::Leaky g_viscosity_constants =
+ LAZY_INSTANCE_INITIALIZER;
+
+base::LazyInstance<SplineConstants>::Leaky g_spline_constants =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+Scroller::Config::Config()
+ : fling_friction(kDefaultFriction),
+ flywheel_enabled(false) {}
+
+Scroller::Scroller(const Config& config)
+ : mode_(UNDEFINED),
+ start_x_(0),
+ start_y_(0),
+ final_x_(0),
+ final_y_(0),
+ min_x_(0),
+ max_x_(0),
+ min_y_(0),
+ max_y_(0),
+ curr_x_(0),
+ curr_y_(0),
+ duration_seconds_reciprocal_(1),
+ delta_x_(0),
+ delta_x_norm_(1),
+ delta_y_(0),
+ delta_y_norm_(1),
+ finished_(true),
+ flywheel_enabled_(config.flywheel_enabled),
+ velocity_(0),
+ curr_velocity_(0),
+ distance_(0),
+ fling_friction_(config.fling_friction),
+ deceleration_(ComputeDeceleration(fling_friction_)),
+ tuning_coeff_(ComputeDeceleration(0.84f)) {}
+
+Scroller::~Scroller() {}
+
+void Scroller::StartScroll(float start_x,
+ float start_y,
+ float dx,
+ float dy,
+ base::TimeTicks start_time) {
+ StartScroll(start_x,
+ start_y,
+ dx,
+ dy,
+ start_time,
+ base::TimeDelta::FromMilliseconds(kDefaultDurationMs));
+}
+
+void Scroller::StartScroll(float start_x,
+ float start_y,
+ float dx,
+ float dy,
+ base::TimeTicks start_time,
+ base::TimeDelta duration) {
+ mode_ = SCROLL_MODE;
+ finished_ = false;
+ duration_ = duration;
+ duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF();
+ start_time_ = start_time;
+ curr_x_ = start_x_ = start_x;
+ curr_y_ = start_y_ = start_y;
+ final_x_ = start_x + dx;
+ final_y_ = start_y + dy;
+ RecomputeDeltas();
+ curr_time_ = start_time_;
+}
+
+void Scroller::Fling(float start_x,
+ float start_y,
+ float velocity_x,
+ float velocity_y,
+ float min_x,
+ float max_x,
+ float min_y,
+ float max_y,
+ base::TimeTicks start_time) {
+ // Continue a scroll or fling in progress.
+ if (flywheel_enabled_ && !finished_) {
+ float old_velocity_x = GetCurrVelocityX();
+ float old_velocity_y = GetCurrVelocityY();
+ if (Signum(velocity_x) == Signum(old_velocity_x) &&
+ Signum(velocity_y) == Signum(old_velocity_y)) {
+ velocity_x += old_velocity_x;
+ velocity_y += old_velocity_y;
+ }
+ }
+
+ mode_ = FLING_MODE;
+ finished_ = false;
+
+ float velocity = std::sqrt(velocity_x * velocity_x + velocity_y * velocity_y);
+
+ velocity_ = velocity;
+ duration_ = GetSplineFlingDuration(velocity);
+ duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF();
+ start_time_ = start_time;
+ curr_time_ = start_time_;
+ curr_x_ = start_x_ = start_x;
+ curr_y_ = start_y_ = start_y;
+
+ float coeff_x = velocity == 0 ? 1.0f : velocity_x / velocity;
+ float coeff_y = velocity == 0 ? 1.0f : velocity_y / velocity;
+
+ double total_distance = GetSplineFlingDistance(velocity);
+ distance_ = total_distance * Signum(velocity);
+
+ min_x_ = min_x;
+ max_x_ = max_x;
+ min_y_ = min_y;
+ max_y_ = max_y;
+
+ final_x_ = start_x + total_distance * coeff_x;
+ final_x_ = Clamped(final_x_, min_x_, max_x_);
+
+ final_y_ = start_y + total_distance * coeff_y;
+ final_y_ = Clamped(final_y_, min_y_, max_y_);
+
+ RecomputeDeltas();
+}
+
+bool Scroller::ComputeScrollOffset(base::TimeTicks time) {
+ if (finished_)
+ return false;
+
+ if (time == curr_time_)
+ return true;
+
+ base::TimeDelta time_passed = time - start_time_;
+
+ if (time_passed < base::TimeDelta()) {
+ time_passed = base::TimeDelta();
+ }
+
+ if (time_passed >= duration_) {
+ curr_x_ = final_x_;
+ curr_y_ = final_y_;
+ curr_time_ = start_time_ + duration_;
+ finished_ = true;
+ return true;
+ }
+
+ curr_time_ = time;
+
+ const float t = time_passed.InSecondsF() * duration_seconds_reciprocal_;
+
+ switch (mode_) {
+ case UNDEFINED:
+ NOTREACHED() << "|StartScroll()| or |Fling()| must be called prior to "
+ "scroll offset computation.";
+ return false;
+
+ case SCROLL_MODE: {
+ float x = g_viscosity_constants.Get().ApplyViscosity(t);
+
+ curr_x_ = start_x_ + x * delta_x_;
+ curr_y_ = start_y_ + x * delta_y_;
+ } break;
+
+ case FLING_MODE: {
+ float distance_coef = 1.f;
+ float velocity_coef = 0.f;
+ g_spline_constants.Get().CalculateCoefficients(
+ t, &distance_coef, &velocity_coef);
+
+ curr_velocity_ = velocity_coef * distance_ * duration_seconds_reciprocal_;
+
+ curr_x_ = start_x_ + distance_coef * delta_x_;
+ curr_x_ = Clamped(curr_x_, min_x_, max_x_);
+
+ curr_y_ = start_y_ + distance_coef * delta_y_;
+ curr_y_ = Clamped(curr_y_, min_y_, max_y_);
+
+ if (ApproxEquals(curr_x_, final_x_) && ApproxEquals(curr_y_, final_y_)) {
+ finished_ = true;
+ }
+ } break;
+ }
+
+ return true;
+}
+
+void Scroller::ExtendDuration(base::TimeDelta extend) {
+ base::TimeDelta passed = GetTimePassed();
+ duration_ = passed + extend;
+ duration_seconds_reciprocal_ = 1.0 / duration_.InSecondsF();
+ finished_ = false;
+}
+
+void Scroller::SetFinalX(float new_x) {
+ final_x_ = new_x;
+ finished_ = false;
+ RecomputeDeltas();
+}
+
+void Scroller::SetFinalY(float new_y) {
+ final_y_ = new_y;
+ finished_ = false;
+ RecomputeDeltas();
+}
+
+void Scroller::AbortAnimation() {
+ curr_x_ = final_x_;
+ curr_y_ = final_y_;
+ curr_velocity_ = 0;
+ curr_time_ = start_time_ + duration_;
+ finished_ = true;
+}
+
+void Scroller::ForceFinished(bool finished) { finished_ = finished; }
+
+bool Scroller::IsFinished() const { return finished_; }
+
+base::TimeDelta Scroller::GetTimePassed() const {
+ return curr_time_ - start_time_;
+}
+
+base::TimeDelta Scroller::GetDuration() const { return duration_; }
+
+float Scroller::GetCurrX() const { return curr_x_; }
+
+float Scroller::GetCurrY() const { return curr_y_; }
+
+float Scroller::GetCurrVelocity() const {
+ if (finished_)
+ return 0;
+ if (mode_ == FLING_MODE)
+ return curr_velocity_;
+ return velocity_ - deceleration_ * GetTimePassed().InSecondsF() * 0.5f;
+}
+
+float Scroller::GetCurrVelocityX() const {
+ return delta_x_norm_ * GetCurrVelocity();
+}
+
+float Scroller::GetCurrVelocityY() const {
+ return delta_y_norm_ * GetCurrVelocity();
+}
+
+float Scroller::GetStartX() const { return start_x_; }
+
+float Scroller::GetStartY() const { return start_y_; }
+
+float Scroller::GetFinalX() const { return final_x_; }
+
+float Scroller::GetFinalY() const { return final_y_; }
+
+bool Scroller::IsScrollingInDirection(float xvel, float yvel) const {
+ return !finished_ && Signum(xvel) == Signum(delta_x_) &&
+ Signum(yvel) == Signum(delta_y_);
+}
+
+void Scroller::RecomputeDeltas() {
+ delta_x_ = final_x_ - start_x_;
+ delta_y_ = final_y_ - start_y_;
+
+ const float hyp = std::sqrt(delta_x_ * delta_x_ + delta_y_ * delta_y_);
+ if (hyp > kEpsilon) {
+ delta_x_norm_ = delta_x_ / hyp;
+ delta_y_norm_ = delta_y_ / hyp;
+ } else {
+ delta_x_norm_ = delta_y_norm_ = 1;
+ }
+}
+
+double Scroller::GetSplineDeceleration(float velocity) const {
+ return std::log(kInflexion * std::abs(velocity) /
+ (fling_friction_ * tuning_coeff_));
+}
+
+base::TimeDelta Scroller::GetSplineFlingDuration(float velocity) const {
+ const double l = GetSplineDeceleration(velocity);
+ const double decel_minus_one = kDecelerationRate - 1.0;
+ const double time_seconds = std::exp(l / decel_minus_one);
+ return base::TimeDelta::FromMicroseconds(time_seconds *
+ base::Time::kMicrosecondsPerSecond);
+}
+
+double Scroller::GetSplineFlingDistance(float velocity) const {
+ const double l = GetSplineDeceleration(velocity);
+ const double decel_minus_one = kDecelerationRate - 1.0;
+ return fling_friction_ * tuning_coeff_ *
+ std::exp(kDecelerationRate / decel_minus_one * l);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/android/scroller.h b/chromium/ui/gfx/android/scroller.h
new file mode 100644
index 00000000000..39d7255dc87
--- /dev/null
+++ b/chromium/ui/gfx/android/scroller.h
@@ -0,0 +1,148 @@
+// 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_ANDROID_SCROLLER_H_
+#define UI_GFX_ANDROID_SCROLLER_H_
+
+#include "base/time/time.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// Native port of android.widget.Scroller.
+// * Change-Id: I4365946f890a76fcfa78ca9d69f2a8e0848095a9
+// * Please update the Change-Id as upstream Android changes are pulled.
+class GFX_EXPORT Scroller {
+ public:
+ struct Config {
+ Config();
+
+ // Controls fling deceleration. Defaults to 0.015f.
+ float fling_friction;
+
+ // Controls fling accumulation. Defaults to disabled.
+ bool flywheel_enabled;
+ };
+
+ explicit Scroller(const Config& config);
+ ~Scroller();
+
+ // Start scrolling by providing a starting point and the distance to travel.
+ // The default value of 250 milliseconds will be used for the duration.
+ void StartScroll(float start_x,
+ float start_y,
+ float dx,
+ float dy,
+ base::TimeTicks start_time);
+
+ // Start scrolling by providing a starting point, the distance to travel,
+ // and the duration of the scroll.
+ void StartScroll(float start_x,
+ float start_y,
+ float dx,
+ float dy,
+ base::TimeTicks start_time,
+ base::TimeDelta duration);
+
+ // Start scrolling based on a fling gesture. The distance travelled will
+ // depend on the initial velocity of the fling.
+ void Fling(float start_x,
+ float start_y,
+ float velocity_x,
+ float velocity_y,
+ float min_x,
+ float max_x,
+ float min_y,
+ float max_y,
+ base::TimeTicks start_time);
+
+ // Call this when you want to know the new location. If it returns true,
+ // the animation is not yet finished.
+ bool ComputeScrollOffset(base::TimeTicks time);
+
+ // Extend the scroll animation by |extend|. This allows a running animation
+ // to scroll further and longer when used with |SetFinalX()| or |SetFinalY()|.
+ void ExtendDuration(base::TimeDelta extend);
+ void SetFinalX(float new_x);
+ void SetFinalY(float new_y);
+
+ // Stops the animation. Contrary to |ForceFinished()|, aborting the animation
+ // causes the scroller to move to the final x and y position.
+ void AbortAnimation();
+
+ // Terminate the scroll without affecting the current x and y positions.
+ void ForceFinished(bool finished);
+
+ // Returns whether the scroller has finished scrolling.
+ bool IsFinished() const;
+
+ // Returns the time elapsed since the beginning of the scrolling.
+ base::TimeDelta GetTimePassed() const;
+
+ // Returns how long the scroll event will take.
+ base::TimeDelta GetDuration() const;
+
+ float GetStartX() const;
+ float GetStartY() const;
+ float GetCurrX() const;
+ float GetCurrY() const;
+ float GetCurrVelocity() const;
+ float GetCurrVelocityX() const;
+ float GetCurrVelocityY() const;
+ float GetFinalX() const;
+ float GetFinalY() const;
+
+ bool IsScrollingInDirection(float xvel, float yvel) const;
+
+ private:
+ enum Mode {
+ UNDEFINED,
+ SCROLL_MODE,
+ FLING_MODE,
+ };
+
+ void OnDurationChanged();
+ void RecomputeDeltas();
+
+ double GetSplineDeceleration(float velocity) const;
+ base::TimeDelta GetSplineFlingDuration(float velocity) const;
+ double GetSplineFlingDistance(float velocity) const;
+
+ Mode mode_;
+
+ float start_x_;
+ float start_y_;
+ float final_x_;
+ float final_y_;
+
+ float min_x_;
+ float max_x_;
+ float min_y_;
+ float max_y_;
+
+ float curr_x_;
+ float curr_y_;
+ base::TimeTicks start_time_;
+ base::TimeTicks curr_time_;
+ base::TimeDelta duration_;
+ double duration_seconds_reciprocal_;
+ float delta_x_;
+ float delta_x_norm_;
+ float delta_y_;
+ float delta_y_norm_;
+ bool finished_;
+ bool flywheel_enabled_;
+
+ float velocity_;
+ float curr_velocity_;
+ float distance_;
+
+ float fling_friction_;
+ float deceleration_;
+ float tuning_coeff_;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_ANDROID_SCROLLER_H_
diff --git a/chromium/ui/gfx/android/scroller_unittest.cc b/chromium/ui/gfx/android/scroller_unittest.cc
new file mode 100644
index 00000000000..9b1018d6ab9
--- /dev/null
+++ b/chromium/ui/gfx/android/scroller_unittest.cc
@@ -0,0 +1,167 @@
+// 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 "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/android/scroller.h"
+
+namespace gfx {
+
+namespace {
+
+const float kDefaultStartX = 7.f;
+const float kDefaultStartY = 25.f;
+const float kDefaultDeltaX = -20.f;
+const float kDefaultDeltaY = 73.f;
+const float kDefaultVelocityX = -35.f;
+const float kDefaultVelocityY = 22.f;
+const float kEpsilon = 1e-3f;
+
+Scroller::Config DefaultConfig() {
+ return Scroller::Config();
+}
+
+} // namespace
+
+class ScrollerTest : public testing::Test {};
+
+TEST_F(ScrollerTest, Scroll) {
+ Scroller scroller(DefaultConfig());
+ base::TimeTicks start_time = base::TimeTicks::Now();
+
+ // Start a scroll and verify initialized values.
+ scroller.StartScroll(kDefaultStartX,
+ kDefaultStartY,
+ kDefaultDeltaX,
+ kDefaultDeltaY,
+ start_time);
+
+ EXPECT_EQ(kDefaultStartX, scroller.GetStartX());
+ EXPECT_EQ(kDefaultStartY, scroller.GetStartY());
+ EXPECT_EQ(kDefaultStartX, scroller.GetCurrX());
+ EXPECT_EQ(kDefaultStartY, scroller.GetCurrY());
+ EXPECT_EQ(kDefaultStartX + kDefaultDeltaX, scroller.GetFinalX());
+ EXPECT_EQ(kDefaultStartY + kDefaultDeltaY, scroller.GetFinalY());
+ EXPECT_FALSE(scroller.IsFinished());
+ EXPECT_EQ(base::TimeDelta(), scroller.GetTimePassed());
+
+ // Advance halfway through the scroll.
+ const base::TimeDelta scroll_duration = scroller.GetDuration();
+ scroller.ComputeScrollOffset(start_time + scroll_duration / 2);
+
+ // Ensure we've moved in the direction of the delta, but have yet to reach
+ // the target.
+ EXPECT_GT(kDefaultStartX, scroller.GetCurrX());
+ EXPECT_LT(kDefaultStartY, scroller.GetCurrY());
+ EXPECT_LT(scroller.GetFinalX(), scroller.GetCurrX());
+ EXPECT_GT(scroller.GetFinalY(), scroller.GetCurrY());
+ EXPECT_FALSE(scroller.IsFinished());
+
+ // Ensure our velocity is non-zero and in the same direction as the delta.
+ EXPECT_GT(0.f, scroller.GetCurrVelocityX() * kDefaultDeltaX);
+ EXPECT_GT(0.f, scroller.GetCurrVelocityY() * kDefaultDeltaY);
+ EXPECT_TRUE(scroller.IsScrollingInDirection(kDefaultDeltaX, kDefaultDeltaY));
+
+ // Repeated offset computations at the same timestamp should yield identical
+ // results.
+ float curr_x = scroller.GetCurrX();
+ float curr_y = scroller.GetCurrY();
+ float curr_velocity_x = scroller.GetCurrVelocityX();
+ float curr_velocity_y = scroller.GetCurrVelocityY();
+ scroller.ComputeScrollOffset(start_time + scroll_duration / 2);
+ EXPECT_EQ(curr_x, scroller.GetCurrX());
+ EXPECT_EQ(curr_y, scroller.GetCurrY());
+ EXPECT_EQ(curr_velocity_x, scroller.GetCurrVelocityX());
+ EXPECT_EQ(curr_velocity_y, scroller.GetCurrVelocityY());
+
+ // Advance to the end.
+ scroller.ComputeScrollOffset(start_time + scroll_duration);
+ EXPECT_EQ(scroller.GetFinalX(), scroller.GetCurrX());
+ EXPECT_EQ(scroller.GetFinalY(), scroller.GetCurrY());
+ EXPECT_TRUE(scroller.IsFinished());
+ EXPECT_EQ(scroll_duration, scroller.GetTimePassed());
+ EXPECT_NEAR(0.f, scroller.GetCurrVelocityX(), kEpsilon);
+ EXPECT_NEAR(0.f, scroller.GetCurrVelocityY(), kEpsilon);
+
+ // Try to advance further; nothing should change.
+ scroller.ComputeScrollOffset(start_time + scroll_duration * 2);
+ EXPECT_EQ(scroller.GetFinalX(), scroller.GetCurrX());
+ EXPECT_EQ(scroller.GetFinalY(), scroller.GetCurrY());
+ EXPECT_TRUE(scroller.IsFinished());
+ EXPECT_EQ(scroll_duration, scroller.GetTimePassed());
+}
+
+TEST_F(ScrollerTest, Fling) {
+ Scroller scroller(DefaultConfig());
+ base::TimeTicks start_time = base::TimeTicks::Now();
+
+ // Start a fling and verify initialized values.
+ scroller.Fling(kDefaultStartX,
+ kDefaultStartY,
+ kDefaultVelocityX,
+ kDefaultVelocityY,
+ INT_MIN,
+ INT_MAX,
+ INT_MIN,
+ INT_MAX,
+ start_time);
+
+ EXPECT_EQ(kDefaultStartX, scroller.GetStartX());
+ EXPECT_EQ(kDefaultStartY, scroller.GetStartY());
+ EXPECT_EQ(kDefaultStartX, scroller.GetCurrX());
+ EXPECT_EQ(kDefaultStartY, scroller.GetCurrY());
+ EXPECT_GT(kDefaultStartX, scroller.GetFinalX());
+ EXPECT_LT(kDefaultStartY, scroller.GetFinalY());
+ EXPECT_FALSE(scroller.IsFinished());
+ EXPECT_EQ(base::TimeDelta(), scroller.GetTimePassed());
+
+ // Advance halfway through the fling.
+ const base::TimeDelta scroll_duration = scroller.GetDuration();
+ scroller.ComputeScrollOffset(start_time + scroll_duration / 2);
+
+ // Ensure we've moved in the direction of the velocity, but have yet to reach
+ // the target.
+ EXPECT_GT(kDefaultStartX, scroller.GetCurrX());
+ EXPECT_LT(kDefaultStartY, scroller.GetCurrY());
+ EXPECT_LT(scroller.GetFinalX(), scroller.GetCurrX());
+ EXPECT_GT(scroller.GetFinalY(), scroller.GetCurrY());
+ EXPECT_FALSE(scroller.IsFinished());
+
+ // Ensure our velocity is non-zero and in the same direction as the original
+ // velocity.
+ EXPECT_LT(0.f, scroller.GetCurrVelocityX() * kDefaultVelocityX);
+ EXPECT_LT(0.f, scroller.GetCurrVelocityY() * kDefaultVelocityY);
+ EXPECT_TRUE(
+ scroller.IsScrollingInDirection(kDefaultVelocityX, kDefaultVelocityY));
+
+ // Repeated offset computations at the same timestamp should yield identical
+ // results.
+ float curr_x = scroller.GetCurrX();
+ float curr_y = scroller.GetCurrY();
+ float curr_velocity_x = scroller.GetCurrVelocityX();
+ float curr_velocity_y = scroller.GetCurrVelocityY();
+ scroller.ComputeScrollOffset(start_time + scroll_duration / 2);
+ EXPECT_EQ(curr_x, scroller.GetCurrX());
+ EXPECT_EQ(curr_y, scroller.GetCurrY());
+ EXPECT_EQ(curr_velocity_x, scroller.GetCurrVelocityX());
+ EXPECT_EQ(curr_velocity_y, scroller.GetCurrVelocityY());
+
+ // Advance to the end.
+ scroller.ComputeScrollOffset(start_time + scroll_duration);
+ EXPECT_EQ(scroller.GetFinalX(), scroller.GetCurrX());
+ EXPECT_EQ(scroller.GetFinalY(), scroller.GetCurrY());
+ EXPECT_TRUE(scroller.IsFinished());
+ EXPECT_EQ(scroll_duration, scroller.GetTimePassed());
+ EXPECT_NEAR(0.f, scroller.GetCurrVelocityX(), kEpsilon);
+ EXPECT_NEAR(0.f, scroller.GetCurrVelocityY(), kEpsilon);
+
+ // Try to advance further; nothing should change.
+ scroller.ComputeScrollOffset(start_time + scroll_duration * 2);
+ EXPECT_EQ(scroller.GetFinalX(), scroller.GetCurrX());
+ EXPECT_EQ(scroller.GetFinalY(), scroller.GetCurrY());
+ EXPECT_TRUE(scroller.IsFinished());
+ EXPECT_EQ(scroll_duration, scroller.GetTimePassed());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/android/shared_device_display_info.cc b/chromium/ui/gfx/android/shared_device_display_info.cc
index 9ac18d0218d..c58813dfcef 100644
--- a/chromium/ui/gfx/android/shared_device_display_info.cc
+++ b/chromium/ui/gfx/android/shared_device_display_info.cc
@@ -16,13 +16,18 @@ static void UpdateSharedDeviceDisplayInfo(JNIEnv* env,
jobject obj,
jint display_height,
jint display_width,
+ jint physical_display_height,
+ jint physical_display_width,
jint bits_per_pixel,
jint bits_per_component,
jdouble dip_scale,
- jint smallest_dip_width) {
+ jint smallest_dip_width,
+ jint rotation_degrees) {
SharedDeviceDisplayInfo::GetInstance()->InvokeUpdate(env, obj,
- display_height, display_width, bits_per_pixel, bits_per_component,
- dip_scale, smallest_dip_width);
+ display_height, display_width,
+ physical_display_height, physical_display_width,
+ bits_per_pixel, bits_per_component,
+ dip_scale, smallest_dip_width, rotation_degrees);
}
// static
@@ -42,6 +47,16 @@ int SharedDeviceDisplayInfo::GetDisplayWidth() {
return display_width_;
}
+int SharedDeviceDisplayInfo::GetPhysicalDisplayHeight() {
+ base::AutoLock autolock(lock_);
+ return physical_display_height_;
+}
+
+int SharedDeviceDisplayInfo::GetPhysicalDisplayWidth() {
+ base::AutoLock autolock(lock_);
+ return physical_display_width_;
+}
+
int SharedDeviceDisplayInfo::GetBitsPerPixel() {
base::AutoLock autolock(lock_);
DCHECK_NE(0, bits_per_pixel_);
@@ -66,6 +81,11 @@ int SharedDeviceDisplayInfo::GetSmallestDIPWidth() {
return smallest_dip_width_;
}
+int SharedDeviceDisplayInfo::GetRotationDegrees() {
+ base::AutoLock autolock(lock_);
+ return rotation_degrees_;
+}
+
// static
bool SharedDeviceDisplayInfo::RegisterSharedDeviceDisplayInfo(JNIEnv* env) {
return RegisterNativesImpl(env);
@@ -75,15 +95,20 @@ void SharedDeviceDisplayInfo::InvokeUpdate(JNIEnv* env,
jobject obj,
jint display_height,
jint display_width,
+ jint physical_display_height,
+ jint physical_display_width,
jint bits_per_pixel,
jint bits_per_component,
jdouble dip_scale,
- jint smallest_dip_width) {
+ jint smallest_dip_width,
+ jint rotation_degrees) {
base::AutoLock autolock(lock_);
- UpdateDisplayInfo(env, obj, display_height,
- display_width, bits_per_pixel, bits_per_component, dip_scale,
- smallest_dip_width);
+ UpdateDisplayInfo(env, obj,
+ display_height, display_width,
+ physical_display_height, physical_display_width,
+ bits_per_pixel, bits_per_component, dip_scale,
+ smallest_dip_width, rotation_degrees);
}
SharedDeviceDisplayInfo::SharedDeviceDisplayInfo()
@@ -95,15 +120,19 @@ SharedDeviceDisplayInfo::SharedDeviceDisplayInfo()
smallest_dip_width_(0) {
JNIEnv* env = base::android::AttachCurrentThread();
j_device_info_.Reset(
- Java_DeviceDisplayInfo_createWithListener(env,
- base::android::GetApplicationContext()));
+ Java_DeviceDisplayInfo_create(
+ env, base::android::GetApplicationContext()));
UpdateDisplayInfo(env, j_device_info_.obj(),
Java_DeviceDisplayInfo_getDisplayHeight(env, j_device_info_.obj()),
Java_DeviceDisplayInfo_getDisplayWidth(env, j_device_info_.obj()),
+ Java_DeviceDisplayInfo_getPhysicalDisplayHeight(env,
+ j_device_info_.obj()),
+ Java_DeviceDisplayInfo_getPhysicalDisplayWidth(env, j_device_info_.obj()),
Java_DeviceDisplayInfo_getBitsPerPixel(env, j_device_info_.obj()),
Java_DeviceDisplayInfo_getBitsPerComponent(env, j_device_info_.obj()),
Java_DeviceDisplayInfo_getDIPScale(env, j_device_info_.obj()),
- Java_DeviceDisplayInfo_getSmallestDIPWidth(env, j_device_info_.obj()));
+ Java_DeviceDisplayInfo_getSmallestDIPWidth(env, j_device_info_.obj()),
+ Java_DeviceDisplayInfo_getRotationDegrees(env, j_device_info_.obj()));
}
SharedDeviceDisplayInfo::~SharedDeviceDisplayInfo() {
@@ -113,16 +142,22 @@ void SharedDeviceDisplayInfo::UpdateDisplayInfo(JNIEnv* env,
jobject jobj,
jint display_height,
jint display_width,
+ jint physical_display_height,
+ jint physical_display_width,
jint bits_per_pixel,
jint bits_per_component,
jdouble dip_scale,
- jint smallest_dip_width) {
+ jint smallest_dip_width,
+ jint rotation_degrees) {
display_height_ = static_cast<int>(display_height);
display_width_ = static_cast<int>(display_width);
+ physical_display_height_ = static_cast<int>(physical_display_height);
+ physical_display_width_ = static_cast<int>(physical_display_width);
bits_per_pixel_ = static_cast<int>(bits_per_pixel);
bits_per_component_ = static_cast<int>(bits_per_component);
dip_scale_ = static_cast<double>(dip_scale);
smallest_dip_width_ = static_cast<int>(smallest_dip_width);
+ rotation_degrees_ = static_cast<int>(rotation_degrees);
}
} // namespace gfx
diff --git a/chromium/ui/gfx/android/shared_device_display_info.h b/chromium/ui/gfx/android/shared_device_display_info.h
index 1e1fc0c6662..e6983e58aa3 100644
--- a/chromium/ui/gfx/android/shared_device_display_info.h
+++ b/chromium/ui/gfx/android/shared_device_display_info.h
@@ -18,12 +18,16 @@ class SharedDeviceDisplayInfo {
public:
static SharedDeviceDisplayInfo* GetInstance();
+ // See documentation in DeviceDisplayInfo.java
int GetDisplayHeight();
int GetDisplayWidth();
+ int GetPhysicalDisplayHeight();
+ int GetPhysicalDisplayWidth();
int GetBitsPerPixel();
int GetBitsPerComponent();
double GetDIPScale();
int GetSmallestDIPWidth();
+ int GetRotationDegrees();
// Registers methods with JNI and returns true if succeeded.
static bool RegisterSharedDeviceDisplayInfo(JNIEnv* env);
@@ -32,10 +36,13 @@ class SharedDeviceDisplayInfo {
jobject jobj,
jint display_height,
jint display_width,
+ jint physical_display_height,
+ jint physical_display_width,
jint bits_per_pixel,
jint bits_per_component,
jdouble dip_scale,
- jint smallest_dip_width);
+ jint smallest_dip_width,
+ jint rotation_degrees);
private:
friend struct DefaultSingletonTraits<SharedDeviceDisplayInfo>;
@@ -45,20 +52,26 @@ class SharedDeviceDisplayInfo {
jobject jobj,
jint display_height,
jint display_width,
+ jint physical_display_height,
+ jint physical_display_width,
jint bits_per_pixel,
jint bits_per_component,
jdouble dip_scale,
- jint smallest_dip_width);
+ jint smallest_dip_width,
+ jint rotation_degrees);
base::Lock lock_;
base::android::ScopedJavaGlobalRef<jobject> j_device_info_;
int display_height_;
int display_width_;
+ int physical_display_height_;
+ int physical_display_width_;
int bits_per_pixel_;
int bits_per_component_;
double dip_scale_;
int smallest_dip_width_;
+ int rotation_degrees_;
DISALLOW_COPY_AND_ASSIGN(SharedDeviceDisplayInfo);
};
diff --git a/chromium/ui/gfx/android/view_configuration.cc b/chromium/ui/gfx/android/view_configuration.cc
index 63657178b15..16c8617ed6b 100644
--- a/chromium/ui/gfx/android/view_configuration.cc
+++ b/chromium/ui/gfx/android/view_configuration.cc
@@ -1,52 +1,206 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
+// 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/android/view_configuration.h"
#include "base/android/jni_android.h"
-#include "jni/ViewConfiguration_jni.h"
+#include "base/lazy_instance.h"
+#include "base/threading/non_thread_safe.h"
+#include "jni/ViewConfigurationHelper_jni.h"
-using namespace JNI_ViewConfiguration;
using base::android::AttachCurrentThread;
using base::android::GetApplicationContext;
namespace gfx {
+namespace {
+
+struct ViewConfigurationData {
+ ViewConfigurationData()
+ : double_tap_timeout_in_ms_(0),
+ long_press_timeout_in_ms_(0),
+ tap_timeout_in_ms_(0),
+ scroll_friction_(1.f),
+ max_fling_velocity_in_pixels_s_(0),
+ min_fling_velocity_in_pixels_s_(0),
+ touch_slop_in_pixels_(0),
+ double_tap_slop_in_pixels_(0),
+ min_scaling_span_in_pixels_(0),
+ min_scaling_touch_major_in_pixels_(0) {
+ JNIEnv* env = AttachCurrentThread();
+ j_view_configuration_helper_.Reset(
+ Java_ViewConfigurationHelper_createWithListener(
+ env, base::android::GetApplicationContext()));
+
+ double_tap_timeout_in_ms_ =
+ Java_ViewConfigurationHelper_getDoubleTapTimeout(env);
+ long_press_timeout_in_ms_ =
+ Java_ViewConfigurationHelper_getLongPressTimeout(env);
+ tap_timeout_in_ms_ = Java_ViewConfigurationHelper_getTapTimeout(env);
+ scroll_friction_ = Java_ViewConfigurationHelper_getScrollFriction(env);
+
+ jobject obj = j_view_configuration_helper_.obj();
+ Update(
+ Java_ViewConfigurationHelper_getScaledMaximumFlingVelocity(env, obj),
+ Java_ViewConfigurationHelper_getScaledMinimumFlingVelocity(env, obj),
+ Java_ViewConfigurationHelper_getScaledTouchSlop(env, obj),
+ Java_ViewConfigurationHelper_getScaledDoubleTapSlop(env, obj),
+ Java_ViewConfigurationHelper_getScaledMinScalingSpan(env, obj),
+ Java_ViewConfigurationHelper_getScaledMinScalingTouchMajor(env, obj));
+ }
+
+ ~ViewConfigurationData() {}
+
+ void SynchronizedUpdate(int scaled_maximum_fling_velocity,
+ int scaled_minimum_fling_velocity,
+ int scaled_touch_slop,
+ int scaled_double_tap_slop,
+ int scaled_min_scaling_span,
+ int scaled_min_scaling_touch_major) {
+ base::AutoLock autolock(lock_);
+ Update(scaled_maximum_fling_velocity,
+ scaled_minimum_fling_velocity,
+ scaled_touch_slop,
+ scaled_double_tap_slop,
+ scaled_min_scaling_span,
+ scaled_min_scaling_touch_major);
+ }
+
+ int double_tap_timeout_in_ms() const { return double_tap_timeout_in_ms_; }
+ int long_press_timeout_in_ms() const { return long_press_timeout_in_ms_; }
+ int tap_timeout_in_ms() const { return tap_timeout_in_ms_; }
+ float scroll_friction() const { return scroll_friction_; }
+
+ int max_fling_velocity_in_pixels_s() {
+ base::AutoLock autolock(lock_);
+ return max_fling_velocity_in_pixels_s_;
+ }
+
+ int min_fling_velocity_in_pixels_s() {
+ base::AutoLock autolock(lock_);
+ return min_fling_velocity_in_pixels_s_;
+ }
+
+ int touch_slop_in_pixels() {
+ base::AutoLock autolock(lock_);
+ return touch_slop_in_pixels_;
+ }
+
+ int double_tap_slop_in_pixels() {
+ base::AutoLock autolock(lock_);
+ return double_tap_slop_in_pixels_;
+ }
+
+ int min_scaling_span_in_pixels() {
+ base::AutoLock autolock(lock_);
+ return min_scaling_span_in_pixels_;
+ }
+
+ int min_scaling_touch_major_in_pixels() {
+ base::AutoLock autolock(lock_);
+ return min_scaling_touch_major_in_pixels_;
+ }
+
+ private:
+ void Update(int scaled_maximum_fling_velocity,
+ int scaled_minimum_fling_velocity,
+ int scaled_touch_slop,
+ int scaled_double_tap_slop,
+ int scaled_min_scaling_span,
+ int scaled_min_scaling_touch_major) {
+ DCHECK_LE(scaled_minimum_fling_velocity, scaled_maximum_fling_velocity);
+ max_fling_velocity_in_pixels_s_ = scaled_maximum_fling_velocity;
+ min_fling_velocity_in_pixels_s_ = scaled_minimum_fling_velocity;
+ touch_slop_in_pixels_ = scaled_touch_slop;
+ double_tap_slop_in_pixels_ = scaled_double_tap_slop;
+ min_scaling_span_in_pixels_ = scaled_min_scaling_span;
+ min_scaling_touch_major_in_pixels_ = scaled_min_scaling_touch_major;
+ }
+
+ base::Lock lock_;
+ base::android::ScopedJavaGlobalRef<jobject> j_view_configuration_helper_;
+
+ // These values will remain constant throughout the lifetime of the app, so
+ // read-access needn't be synchronized.
+ int double_tap_timeout_in_ms_;
+ int long_press_timeout_in_ms_;
+ int tap_timeout_in_ms_;
+ float scroll_friction_;
+
+ // These values may vary as view-specific parameters (DPI scale) are changed,
+ // so read/write access must be synchronized.
+ int max_fling_velocity_in_pixels_s_;
+ int min_fling_velocity_in_pixels_s_;
+ int touch_slop_in_pixels_;
+ int double_tap_slop_in_pixels_;
+ int min_scaling_span_in_pixels_;
+ int min_scaling_touch_major_in_pixels_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ViewConfigurationData);
+};
+
+// Leaky to allow access from any thread.
+base::LazyInstance<ViewConfigurationData>::Leaky g_view_configuration =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+static void UpdateSharedViewConfiguration(JNIEnv* env,
+ jobject obj,
+ jint scaled_maximum_fling_velocity,
+ jint scaled_minimum_fling_velocity,
+ jint scaled_touch_slop,
+ jint scaled_double_tap_slop,
+ jint scaled_min_scaling_span,
+ jint scaled_min_scaling_touch_major) {
+ g_view_configuration.Get().SynchronizedUpdate(scaled_maximum_fling_velocity,
+ scaled_minimum_fling_velocity,
+ scaled_touch_slop,
+ scaled_double_tap_slop,
+ scaled_min_scaling_span,
+ scaled_min_scaling_touch_major);
+}
+
int ViewConfiguration::GetDoubleTapTimeoutInMs() {
- JNIEnv* env = AttachCurrentThread();
- return Java_ViewConfiguration_getDoubleTapTimeout(env);
+ return g_view_configuration.Get().double_tap_timeout_in_ms();
}
int ViewConfiguration::GetLongPressTimeoutInMs() {
- JNIEnv* env = AttachCurrentThread();
- return Java_ViewConfiguration_getLongPressTimeout(env);
+ return g_view_configuration.Get().long_press_timeout_in_ms();
}
int ViewConfiguration::GetTapTimeoutInMs() {
- JNIEnv* env = AttachCurrentThread();
- return Java_ViewConfiguration_getTapTimeout(env);
+ return g_view_configuration.Get().tap_timeout_in_ms();
+}
+
+float ViewConfiguration::GetScrollFriction() {
+ return g_view_configuration.Get().scroll_friction();
}
int ViewConfiguration::GetMaximumFlingVelocityInPixelsPerSecond() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> view =
- Java_ViewConfiguration_get(env, GetApplicationContext());
- return Java_ViewConfiguration_getScaledMaximumFlingVelocity(env, view.obj());
+ return g_view_configuration.Get().max_fling_velocity_in_pixels_s();
}
int ViewConfiguration::GetMinimumFlingVelocityInPixelsPerSecond() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> view =
- Java_ViewConfiguration_get(env, GetApplicationContext());
- return Java_ViewConfiguration_getScaledMinimumFlingVelocity(env, view.obj());
+ return g_view_configuration.Get().min_fling_velocity_in_pixels_s();
}
int ViewConfiguration::GetTouchSlopInPixels() {
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jobject> view =
- Java_ViewConfiguration_get(env, GetApplicationContext());
- return Java_ViewConfiguration_getScaledTouchSlop(env, view.obj());
+ return g_view_configuration.Get().touch_slop_in_pixels();
+}
+
+int ViewConfiguration::GetDoubleTapSlopInPixels() {
+ return g_view_configuration.Get().double_tap_slop_in_pixels();
+}
+
+int ViewConfiguration::GetMinScalingSpanInPixels() {
+ return g_view_configuration.Get().min_scaling_span_in_pixels();
+}
+
+int ViewConfiguration::GetMinScalingTouchMajorInPixels() {
+ return g_view_configuration.Get().min_scaling_touch_major_in_pixels();
}
bool ViewConfiguration::RegisterViewConfiguration(JNIEnv* env) {
diff --git a/chromium/ui/gfx/android/view_configuration.h b/chromium/ui/gfx/android/view_configuration.h
index f0995cb3e29..4595071c4f1 100644
--- a/chromium/ui/gfx/android/view_configuration.h
+++ b/chromium/ui/gfx/android/view_configuration.h
@@ -12,16 +12,24 @@
namespace gfx {
// Provides access to Android's ViewConfiguration for gesture-related constants.
+// Note: All methods may be safely called from any thread.
class GFX_EXPORT ViewConfiguration {
public:
static int GetDoubleTapTimeoutInMs();
static int GetLongPressTimeoutInMs();
static int GetTapTimeoutInMs();
+ // Dimensionless coefficient of friction.
+ static float GetScrollFriction();
+
static int GetMaximumFlingVelocityInPixelsPerSecond();
static int GetMinimumFlingVelocityInPixelsPerSecond();
static int GetTouchSlopInPixels();
+ static int GetDoubleTapSlopInPixels();
+
+ static int GetMinScalingSpanInPixels();
+ static int GetMinScalingTouchMajorInPixels();
// Registers methods with JNI and returns true if succeeded.
static bool RegisterViewConfiguration(JNIEnv* env);
diff --git a/chromium/ui/gfx/animation/animation.cc b/chromium/ui/gfx/animation/animation.cc
index 3b525f22f00..fce72e8fce5 100644
--- a/chromium/ui/gfx/animation/animation.cc
+++ b/chromium/ui/gfx/animation/animation.cc
@@ -106,8 +106,9 @@ bool Animation::ShouldRenderRichAnimation() {
}
}
return !::GetSystemMetrics(SM_REMOTESESSION);
-#endif
+#else
return true;
+#endif
}
bool Animation::ShouldSendCanceledFromStop() {
diff --git a/chromium/ui/gfx/animation/animation_delegate.h b/chromium/ui/gfx/animation/animation_delegate.h
index 94303ddd93a..b1e88d2fdac 100644
--- a/chromium/ui/gfx/animation/animation_delegate.h
+++ b/chromium/ui/gfx/animation/animation_delegate.h
@@ -17,6 +17,8 @@ class Animation;
// state of an animation.
class GFX_EXPORT AnimationDelegate {
public:
+ virtual ~AnimationDelegate() {}
+
// Called when an animation has completed.
virtual void AnimationEnded(const Animation* animation) {}
@@ -25,9 +27,6 @@ class GFX_EXPORT AnimationDelegate {
// Called when an animation has been canceled.
virtual void AnimationCanceled(const Animation* animation) {}
-
- protected:
- virtual ~AnimationDelegate() {}
};
} // namespace gfx
diff --git a/chromium/ui/gfx/animation/tween.cc b/chromium/ui/gfx/animation/tween.cc
index 174305078c2..483d772b5b4 100644
--- a/chromium/ui/gfx/animation/tween.cc
+++ b/chromium/ui/gfx/animation/tween.cc
@@ -14,6 +14,7 @@
#include "base/basictypes.h"
#include "base/logging.h"
+#include "ui/gfx/geometry/cubic_bezier.h"
#include "ui/gfx/safe_integer_conversions.h"
namespace gfx {
@@ -51,6 +52,15 @@ double Tween::CalculateValue(Tween::Type type, double state) {
case SMOOTH_IN_OUT:
return sin(state);
+ case FAST_OUT_SLOW_IN:
+ return gfx::CubicBezier(0.4, 0, 0.2, 1).Solve(state);
+
+ case LINEAR_OUT_SLOW_IN:
+ return gfx::CubicBezier(0, 0, .2, 1).Solve(state);
+
+ case FAST_OUT_LINEAR_IN:
+ return gfx::CubicBezier(0.4, 0, 1, 1).Solve(state);
+
case ZERO:
return 0;
}
diff --git a/chromium/ui/gfx/animation/tween.h b/chromium/ui/gfx/animation/tween.h
index 04f353db1ae..8b079ac73cb 100644
--- a/chromium/ui/gfx/animation/tween.h
+++ b/chromium/ui/gfx/animation/tween.h
@@ -16,15 +16,22 @@ namespace gfx {
class GFX_EXPORT Tween {
public:
enum Type {
- LINEAR, // Linear.
- EASE_OUT, // Fast in, slow out (default).
- EASE_IN, // Slow in, fast out.
- EASE_IN_2, // Variant of EASE_IN that starts out slower.
- EASE_IN_OUT, // Slow in and out, fast in the middle.
- FAST_IN_OUT, // Fast in and out, slow in the middle.
- EASE_OUT_SNAP, // Fast in, slow out, snap to final value.
- SMOOTH_IN_OUT, // Smooth, consistent speeds in and out (sine wave).
- ZERO, // Returns a value of 0 always.
+ LINEAR, // Linear.
+ EASE_OUT, // Fast in, slow out (default).
+ EASE_IN, // Slow in, fast out.
+ EASE_IN_2, // Variant of EASE_IN that starts out slower than
+ // EASE_IN.
+ EASE_IN_OUT, // Slow in and out, fast in the middle.
+ FAST_IN_OUT, // Fast in and out, slow in the middle.
+ EASE_OUT_SNAP, // Fast in, slow out, snap to final value.
+ SMOOTH_IN_OUT, // Smooth, consistent speeds in and out (sine wave).
+ FAST_OUT_SLOW_IN, // Variant of EASE_IN_OUT which should be used in most
+ // cases.
+ LINEAR_OUT_SLOW_IN, // Variant of EASE_OUT which should be used for
+ // fading in from 0% or motion when entering a scene.
+ FAST_OUT_LINEAR_IN, // Variant of EASE_IN which should should be used for
+ // fading out to 0% or motion when exiting a scene.
+ ZERO, // Returns a value of 0 always.
};
// Returns the value based on the tween type. |state| is from 0-1.
diff --git a/chromium/ui/gfx/animation/tween_unittest.cc b/chromium/ui/gfx/animation/tween_unittest.cc
index d92fe1bacc4..f71a77dccbd 100644
--- a/chromium/ui/gfx/animation/tween_unittest.cc
+++ b/chromium/ui/gfx/animation/tween_unittest.cc
@@ -11,16 +11,19 @@
#endif
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/test/color_util.h"
+#include "ui/gfx/test/gfx_util.h"
namespace gfx {
namespace {
double next_double(double d) {
#if defined(OS_WIN)
- return _nextafter(d, d+1);
+ return _nextafter(d, d + 1);
#else
- return nextafter(d, d+1);
+ // Step two units of least precision towards positive infinity. On some 32
+ // bit x86 compilers a single step was not enough due to loss of precision in
+ // optimized code.
+ return nextafter(nextafter(d, d + 1), d + 1);
#endif
}
diff --git a/chromium/ui/gfx/blit.cc b/chromium/ui/gfx/blit.cc
index 4b87bc9aac5..653c56bda7f 100644
--- a/chromium/ui/gfx/blit.cc
+++ b/chromium/ui/gfx/blit.cc
@@ -29,21 +29,28 @@ namespace {
// Returns true if the given canvas has any part of itself clipped out or
// any non-identity tranform.
-bool HasClipOrTransform(const SkCanvas& canvas) {
+bool HasClipOrTransform(SkCanvas& canvas) {
if (!canvas.getTotalMatrix().isIdentity())
return true;
- const SkRegion& clip_region = canvas.getTotalClip();
- if (clip_region.isEmpty() || clip_region.isComplex())
+ if (!canvas.isClipRect())
return true;
// Now we know the clip is a regular rectangle, make sure it covers the
// entire canvas.
- const SkBitmap& bitmap = skia::GetTopDevice(canvas)->accessBitmap(false);
- const SkIRect& clip_bounds = clip_region.getBounds();
+ SkIRect clip_bounds;
+ canvas.getClipDeviceBounds(&clip_bounds);
+
+ SkImageInfo info;
+ size_t row_bytes;
+ void* pixels = canvas.accessTopLayerPixels(&info, &row_bytes);
+ DCHECK(pixels);
+ if (!pixels)
+ return true;
+
if (clip_bounds.fLeft != 0 || clip_bounds.fTop != 0 ||
- clip_bounds.fRight != bitmap.width() ||
- clip_bounds.fBottom != bitmap.height())
+ clip_bounds.fRight != info.width() ||
+ clip_bounds.fBottom != info.height())
return true;
return false;
diff --git a/chromium/ui/gfx/box_f.h b/chromium/ui/gfx/box_f.h
index 73e0972f662..47d822eb33f 100644
--- a/chromium/ui/gfx/box_f.h
+++ b/chromium/ui/gfx/box_f.h
@@ -2,159 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_BOX_F_H_
-#define UI_GFX_BOX_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/box_f.h"
-#include "ui/gfx/point3_f.h"
-#include "ui/gfx/vector3d_f.h"
-
-namespace gfx {
-
-// A 3d version of gfx::RectF, with the positive z-axis pointed towards
-// the camera.
-class GFX_EXPORT BoxF {
- public:
- BoxF()
- : width_(0.f),
- height_(0.f),
- depth_(0.f) {}
-
- BoxF(float width, float height, float depth)
- : width_(width < 0 ? 0 : width),
- height_(height < 0 ? 0 : height),
- depth_(depth < 0 ? 0 : depth) {}
-
- BoxF(float x, float y, float z, float width, float height, float depth)
- : origin_(x, y, z),
- width_(width < 0 ? 0 : width),
- height_(height < 0 ? 0 : height),
- depth_(depth < 0 ? 0 : depth) {}
-
- BoxF(const Point3F& origin, float width, float height, float depth)
- : origin_(origin),
- width_(width < 0 ? 0 : width),
- height_(height < 0 ? 0 : height),
- depth_(depth < 0 ? 0 : depth) {}
-
- ~BoxF() {}
-
- // Scales all three axes by the given scale.
- void Scale(float scale) {
- Scale(scale, scale, scale);
- }
-
- // Scales each axis by the corresponding given scale.
- void Scale(float x_scale, float y_scale, float z_scale) {
- origin_.Scale(x_scale, y_scale, z_scale);
- set_size(width_ * x_scale, height_ * y_scale, depth_ * z_scale);
- }
-
- // Moves the box by the specified distance in each dimension.
- void operator+=(const Vector3dF& offset) {
- origin_ += offset;
- }
-
- // Returns true if the box has no interior points.
- bool IsEmpty() const;
-
- // Computes the union of this box with the given box. The union is the
- // smallest box that contains both boxes.
- void Union(const BoxF& box);
-
- std::string ToString() const;
-
- float x() const { return origin_.x(); }
- void set_x(float x) { origin_.set_x(x); }
-
- float y() const { return origin_.y(); }
- void set_y(float y) { origin_.set_y(y); }
-
- float z() const { return origin_.z(); }
- void set_z(float z) { origin_.set_z(z); }
-
- float width() const { return width_; }
- void set_width(float width) { width_ = width < 0 ? 0 : width; }
-
- float height() const { return height_; }
- void set_height(float height) { height_ = height < 0 ? 0 : height; }
-
- float depth() const { return depth_; }
- void set_depth(float depth) { depth_ = depth < 0 ? 0 : depth; }
-
- float right() const { return x() + width(); }
- float bottom() const { return y() + height(); }
- float front() const { return z() + depth(); }
-
- void set_size(float width, float height, float depth) {
- width_ = width < 0 ? 0 : width;
- height_ = height < 0 ? 0 : height;
- depth_ = depth < 0 ? 0 : depth;
- }
-
- const Point3F& origin() const { return origin_; }
- void set_origin(const Point3F& origin) { origin_ = origin; }
-
- // Expands |this| to contain the given point, if necessary. Please note, even
- // if |this| is empty, after the function |this| will continue to contain its
- // |origin_|.
- void ExpandTo(const Point3F& point);
-
- // Expands |this| to contain the given box, if necessary. Please note, even
- // if |this| is empty, after the function |this| will continue to contain its
- // |origin_|.
- void ExpandTo(const BoxF& box);
-
- private:
- // Expands the box to contain the two given points. It is required that each
- // component of |min| is less than or equal to the corresponding component in
- // |max|. Precisely, what this function does is ensure that after the function
- // completes, |this| contains origin_, min, max, and origin_ + (width_,
- // height_, depth_), even if the box is empty. Emptiness checks are handled in
- // the public function Union.
- void ExpandTo(const Point3F& min, const Point3F& max);
-
- Point3F origin_;
- float width_;
- float height_;
- float depth_;
-};
-
-GFX_EXPORT BoxF UnionBoxes(const BoxF& a, const BoxF& b);
-
-inline BoxF ScaleBox(const BoxF& b,
- float x_scale,
- float y_scale,
- float z_scale) {
- return BoxF(b.x() * x_scale,
- b.y() * y_scale,
- b.z() * z_scale,
- b.width() * x_scale,
- b.height() * y_scale,
- b.depth() * z_scale);
-}
-
-inline BoxF ScaleBox(const BoxF& b, float scale) {
- return ScaleBox(b, scale, scale, scale);
-}
-
-inline bool operator==(const BoxF& a, const BoxF& b) {
- return a.origin() == b.origin() && a.width() == b.width() &&
- a.height() == b.height() && a.depth() == b.depth();
-}
-
-inline bool operator!=(const BoxF& a, const BoxF& b) {
- return !(a == b);
-}
-
-inline BoxF operator+(const BoxF& b, const Vector3dF& v) {
- return BoxF(b.x() + v.x(),
- b.y() + v.y(),
- b.z() + v.z(),
- b.width(),
- b.height(),
- b.depth());
-}
-
-} // namespace gfx
-
-#endif // UI_GFX_BOX_F_H_
diff --git a/chromium/ui/gfx/canvas.cc b/chromium/ui/gfx/canvas.cc
index b89efa9e2b7..db8b28fc0a9 100644
--- a/chromium/ui/gfx/canvas.cc
+++ b/chromium/ui/gfx/canvas.cc
@@ -11,7 +11,6 @@
#include "base/logging.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
-#include "ui/gfx/canvas.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size_conversions.h"
@@ -99,16 +98,6 @@ void Canvas::SizeStringInt(const base::string16& text,
}
// static
-void Canvas::SizeStringInt(const base::string16& text,
- const Font& font,
- int* width,
- int* height,
- int line_height,
- int flags) {
- SizeStringInt(text, FontList(font), width, height, line_height, flags);
-}
-
-// static
int Canvas::GetStringWidth(const base::string16& text,
const FontList& font_list) {
int width = 0, height = 0;
@@ -125,39 +114,19 @@ float Canvas::GetStringWidthF(const base::string16& text,
}
// static
-int Canvas::GetStringWidth(const base::string16& text, const Font& font) {
- int width = 0, height = 0;
- SizeStringInt(text, FontList(font), &width, &height, 0, NO_ELLIPSIS);
- return width;
-}
-
-// static
int Canvas::DefaultCanvasTextAlignment() {
return base::i18n::IsRTL() ? TEXT_ALIGN_RIGHT : TEXT_ALIGN_LEFT;
}
-void Canvas::DrawStringWithHalo(const base::string16& text,
- const Font& font,
- SkColor text_color,
- SkColor halo_color_in,
- int x,
- int y,
- int w,
- int h,
- int flags) {
- DrawStringRectWithHalo(text, FontList(font), text_color, halo_color_in,
- Rect(x, y, w, h), flags);
-}
-
ImageSkiaRep Canvas::ExtractImageRep() const {
- const SkBitmap& device_bitmap = canvas_->getDevice()->accessBitmap(false);
-
// Make a bitmap to return, and a canvas to draw into it. We don't just want
// to call extractSubset or the copy constructor, since we want an actual copy
// of the bitmap.
+ const SkISize size = canvas_->getDeviceSize();
SkBitmap result;
- device_bitmap.copyTo(&result, SkBitmap::kARGB_8888_Config);
+ result.allocN32Pixels(size.width(), size.height());
+ canvas_->readPixels(&result, 0, 0);
return ImageSkiaRep(result, image_scale_);
}
@@ -175,8 +144,7 @@ void Canvas::DrawDashedRect(const Rect& rect, SkColor color) {
delete dots;
last_color = color;
dots = new SkBitmap;
- dots->setConfig(SkBitmap::kARGB_8888_Config, col_pixels, row_pixels);
- dots->allocPixels();
+ dots->allocN32Pixels(col_pixels, row_pixels);
dots->eraseARGB(0, 0, 0, 0);
uint32_t* dot = dots->getAddr32(0, 0);
@@ -216,7 +184,6 @@ void Canvas::SaveLayerAlpha(uint8 alpha) {
canvas_->saveLayerAlpha(NULL, alpha);
}
-
void Canvas::SaveLayerAlpha(uint8 alpha, const Rect& layer_bounds) {
SkRect bounds(RectToSkRect(layer_bounds));
canvas_->saveLayerAlpha(&bounds, alpha);
@@ -226,12 +193,16 @@ void Canvas::Restore() {
canvas_->restore();
}
-bool Canvas::ClipRect(const Rect& rect) {
- return canvas_->clipRect(RectToSkRect(rect));
+void Canvas::ClipRect(const Rect& rect) {
+ canvas_->clipRect(RectToSkRect(rect));
+}
+
+void Canvas::ClipPath(const SkPath& path, bool do_anti_alias) {
+ canvas_->clipPath(path, SkRegion::kIntersect_Op, do_anti_alias);
}
-bool Canvas::ClipPath(const SkPath& path) {
- return canvas_->clipPath(path);
+bool Canvas::IsClipEmpty() const {
+ return canvas_->isClipEmpty();
}
bool Canvas::GetClipBounds(Rect* bounds) {
@@ -363,7 +334,7 @@ void Canvas::DrawImageInt(const ImageSkia& image,
int x,
int y,
const SkPaint& paint) {
- const ImageSkiaRep& image_rep = GetImageRepToPaint(image);
+ const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
if (image_rep.is_null())
return;
const SkBitmap& bitmap = image_rep.sk_bitmap();
@@ -405,63 +376,65 @@ void Canvas::DrawImageInt(const ImageSkia& image,
int dest_h,
bool filter,
const SkPaint& paint) {
- DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() &&
- src_y + src_h < std::numeric_limits<int16_t>::max());
- if (src_w <= 0 || src_h <= 0) {
- NOTREACHED() << "Attempting to draw bitmap from an empty rect!";
- return;
- }
-
- if (!IntersectsClipRectInt(dest_x, dest_y, dest_w, dest_h))
- return;
-
- float user_scale_x = static_cast<float>(dest_w) / src_w;
- float user_scale_y = static_cast<float>(dest_h) / src_h;
-
- const ImageSkiaRep& image_rep = GetImageRepToPaint(image,
- user_scale_x, user_scale_y);
- if (image_rep.is_null())
- return;
-
- SkRect dest_rect = { SkIntToScalar(dest_x),
- SkIntToScalar(dest_y),
- SkIntToScalar(dest_x + dest_w),
- SkIntToScalar(dest_y + dest_h) };
-
- if (src_w == dest_w && src_h == dest_h &&
- user_scale_x == 1.0f && user_scale_y == 1.0f &&
- image_rep.scale() == 1.0f) {
- // Workaround for apparent bug in Skia that causes image to occasionally
- // shift.
- SkIRect src_rect = { src_x, src_y, src_x + src_w, src_y + src_h };
- const SkBitmap& bitmap = image_rep.sk_bitmap();
- canvas_->drawBitmapRect(bitmap, &src_rect, dest_rect, &paint);
- return;
- }
-
- // Make a bitmap shader that contains the bitmap we want to draw. This is
- // basically what SkCanvas.drawBitmap does internally, but it gives us
- // more control over quality and will use the mipmap in the source image if
- // it has one, whereas drawBitmap won't.
- SkMatrix shader_scale;
- shader_scale.setScale(SkFloatToScalar(user_scale_x),
- SkFloatToScalar(user_scale_y));
- shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
- shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
-
- skia::RefPtr<SkShader> shader = CreateImageRepShader(
- image_rep,
- SkShader::kRepeat_TileMode,
- shader_scale);
-
- // Set up our paint to use the shader & release our reference (now just owned
- // by the paint).
- SkPaint p(paint);
- p.setFilterBitmap(filter);
- p.setShader(shader.get());
-
- // The rect will be filled by the bitmap.
- canvas_->drawRect(dest_rect, p);
+ DrawImageIntHelper(image, src_x, src_y, src_w, src_h, dest_x, dest_y, dest_w,
+ dest_h, filter, paint, image_scale_, false);
+}
+
+void Canvas::DrawImageIntInPixel(const ImageSkia& image,
+ int src_x,
+ int src_y,
+ int src_w,
+ int src_h,
+ int dest_x,
+ int dest_y,
+ int dest_w,
+ int dest_h,
+ bool filter,
+ const SkPaint& paint) {
+ // All values passed into this function are in pixels, i.e. no scaling needs
+ // be done.
+ // Logic as below:-
+ // 1. Get the matrix transform from the canvas.
+ // 2. Set the scale in the matrix to 1.0 while honoring the direction of the
+ // the scale (x/y). Example RTL layouts.
+ // 3. Round off the X and Y translation components in the matrix. This is to
+ // reduce floating point errors during rect transformation. This is needed
+ // for fractional scale factors like 1.25/1.5, etc.
+ // 4. Save the current state of the canvas.
+ // 5. Set the modified matrix in the canvas. This ensures that no scaling
+ // will be done for draw operations on the canvas.
+ // 6. Draw the image.
+ // 7. Restore the state of the canvas and the SkCanvas matrix stack.
+ SkMatrix matrix = canvas_->getTotalMatrix();
+
+ // Ensure that the direction of the x and y scales is preserved. This is
+ // important for RTL layouts.
+ matrix.getScaleX() > 0 ? matrix.setScaleX(1.0f) : matrix.setScaleX(-1.0f);
+ matrix.getScaleY() > 0 ? matrix.setScaleY(1.0f) : matrix.setScaleY(-1.0f);
+
+ matrix.setTranslateX(SkScalarRoundToInt(matrix.getTranslateX()));
+ matrix.setTranslateY(SkScalarRoundToInt(matrix.getTranslateY()));
+
+ Save();
+
+ canvas_->setMatrix(matrix);
+
+ DrawImageIntHelper(image,
+ src_x,
+ src_y,
+ src_w,
+ src_h,
+ dest_x,
+ dest_y,
+ dest_w,
+ dest_h,
+ filter,
+ paint,
+ image_scale_,
+ true);
+
+ // Restore the state of the canvas.
+ Restore();
}
void Canvas::DrawImageInPath(const ImageSkia& image,
@@ -469,7 +442,7 @@ void Canvas::DrawImageInPath(const ImageSkia& image,
int y,
const SkPath& path,
const SkPaint& paint) {
- const ImageSkiaRep& image_rep = GetImageRepToPaint(image);
+ const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
if (image_rep.is_null())
return;
@@ -502,47 +475,6 @@ void Canvas::DrawStringRectWithFlags(const base::string16& text,
ShadowValues());
}
-void Canvas::DrawStringInt(const base::string16& text,
- const Font& font,
- SkColor color,
- int x,
- int y,
- int w,
- int h) {
- DrawStringInt(text, font, color, x, y, w, h, DefaultCanvasTextAlignment());
-}
-
-void Canvas::DrawStringInt(const base::string16& text,
- const Font& font,
- SkColor color,
- const Rect& display_rect) {
- DrawStringInt(text, font, color, display_rect.x(), display_rect.y(),
- display_rect.width(), display_rect.height());
-}
-
-void Canvas::DrawStringInt(const base::string16& text,
- const Font& font,
- SkColor color,
- int x,
- int y,
- int w,
- int h,
- int flags) {
- DrawStringWithShadows(text, font, color, Rect(x, y, w, h), 0, flags,
- ShadowValues());
-}
-
-void Canvas::DrawStringWithShadows(const base::string16& text,
- const Font& font,
- SkColor color,
- const Rect& text_bounds,
- int line_height,
- int flags,
- const ShadowValues& shadows) {
- DrawStringRectWithShadows(text, FontList(font), color, text_bounds,
- line_height, flags, shadows);
-}
-
void Canvas::TileImageInt(const ImageSkia& image,
int x,
int y,
@@ -573,8 +505,7 @@ void Canvas::TileImageInt(const ImageSkia& image,
if (!IntersectsClipRectInt(dest_x, dest_y, w, h))
return;
- const ImageSkiaRep& image_rep = GetImageRepToPaint(
- image, tile_scale_x, tile_scale_y);
+ const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
if (image_rep.is_null())
return;
@@ -631,29 +562,77 @@ bool Canvas::IntersectsClipRect(const Rect& rect) {
rect.width(), rect.height());
}
-const ImageSkiaRep& Canvas::GetImageRepToPaint(const ImageSkia& image) const {
- return GetImageRepToPaint(image, 1.0f, 1.0f);
-}
+void Canvas::DrawImageIntHelper(const ImageSkia& image,
+ int src_x,
+ int src_y,
+ int src_w,
+ int src_h,
+ int dest_x,
+ int dest_y,
+ int dest_w,
+ int dest_h,
+ bool filter,
+ const SkPaint& paint,
+ float image_scale,
+ bool pixel) {
+ DLOG_ASSERT(src_x + src_w < std::numeric_limits<int16_t>::max() &&
+ src_y + src_h < std::numeric_limits<int16_t>::max());
+ if (src_w <= 0 || src_h <= 0) {
+ NOTREACHED() << "Attempting to draw bitmap from an empty rect!";
+ return;
+ }
-const ImageSkiaRep& Canvas::GetImageRepToPaint(
- const ImageSkia& image,
- float user_additional_scale_x,
- float user_additional_scale_y) const {
- const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_);
+ if (!IntersectsClipRectInt(dest_x, dest_y, dest_w, dest_h))
+ return;
+
+ float user_scale_x = static_cast<float>(dest_w) / src_w;
+ float user_scale_y = static_cast<float>(dest_h) / src_h;
+
+ const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale);
+ if (image_rep.is_null())
+ return;
- if (!image_rep.is_null()) {
- SkMatrix m = canvas_->getTotalMatrix();
- float scale_x = SkScalarToFloat(SkScalarAbs(m.getScaleX())) *
- user_additional_scale_x;
- float scale_y = SkScalarToFloat(SkScalarAbs(m.getScaleY())) *
- user_additional_scale_y;
+ SkRect dest_rect = { SkIntToScalar(dest_x),
+ SkIntToScalar(dest_y),
+ SkIntToScalar(dest_x + dest_w),
+ SkIntToScalar(dest_y + dest_h) };
- float bitmap_scale = image_rep.scale();
- if (scale_x < bitmap_scale || scale_y < bitmap_scale)
- const_cast<SkBitmap&>(image_rep.sk_bitmap()).buildMipMap();
+ if (src_w == dest_w && src_h == dest_h &&
+ user_scale_x == 1.0f && user_scale_y == 1.0f &&
+ image_rep.scale() == 1.0f && !pixel) {
+ // Workaround for apparent bug in Skia that causes image to occasionally
+ // shift.
+ SkIRect src_rect = { src_x, src_y, src_x + src_w, src_y + src_h };
+ const SkBitmap& bitmap = image_rep.sk_bitmap();
+ canvas_->drawBitmapRect(bitmap, &src_rect, dest_rect, &paint);
+ return;
}
- return image_rep;
+ // Make a bitmap shader that contains the bitmap we want to draw. This is
+ // basically what SkCanvas.drawBitmap does internally, but it gives us
+ // more control over quality and will use the mipmap in the source image if
+ // it has one, whereas drawBitmap won't.
+ SkMatrix shader_scale;
+ shader_scale.setScale(SkFloatToScalar(user_scale_x),
+ SkFloatToScalar(user_scale_y));
+ shader_scale.preTranslate(SkIntToScalar(-src_x), SkIntToScalar(-src_y));
+ shader_scale.postTranslate(SkIntToScalar(dest_x), SkIntToScalar(dest_y));
+
+ skia::RefPtr<SkShader> shader = CreateImageRepShaderForScale(
+ image_rep,
+ SkShader::kRepeat_TileMode,
+ shader_scale,
+ pixel ? 1.0f : image_rep.scale());
+
+ // Set up our paint to use the shader & release our reference (now just owned
+ // by the paint).
+ SkPaint p(paint);
+ p.setFilterLevel(filter ? SkPaint::kLow_FilterLevel
+ : SkPaint::kNone_FilterLevel);
+ p.setShader(shader.get());
+
+ // The rect will be filled by the bitmap.
+ canvas_->drawRect(dest_rect, p);
}
} // namespace gfx
diff --git a/chromium/ui/gfx/canvas.h b/chromium/ui/gfx/canvas.h
index f8193f1134c..f3d9486f9a6 100644
--- a/chromium/ui/gfx/canvas.h
+++ b/chromium/ui/gfx/canvas.h
@@ -15,11 +15,11 @@
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/shadow_value.h"
+#include "ui/gfx/text_constants.h"
namespace gfx {
class Rect;
-class Font;
class FontList;
class Point;
class Size;
@@ -40,12 +40,7 @@ class Transform;
// of kSrcOver_Mode.
class GFX_EXPORT Canvas {
public:
- enum TruncateFadeMode {
- TruncateFadeTail,
- TruncateFadeHead,
- };
-
- // Specifies the alignment for text rendered with the DrawStringInt method.
+ // Specifies the alignment for text rendered with the DrawStringRect method.
enum {
TEXT_ALIGN_LEFT = 1 << 0,
TEXT_ALIGN_CENTER = 1 << 1,
@@ -54,7 +49,7 @@ class GFX_EXPORT Canvas {
// Specifies the text consists of multiple lines.
MULTI_LINE = 1 << 3,
- // By default DrawStringInt does not process the prefix ('&') character
+ // By default DrawStringRect does not process the prefix ('&') character
// specially. That is, the string "&foo" is rendered as "&foo". When
// rendering text from a resource that uses the prefix character for
// mnemonics, the prefix should be processed and can be rendered as an
@@ -69,7 +64,7 @@ class GFX_EXPORT Canvas {
// This only works with MULTI_LINE.
CHARACTER_BREAK = 1 << 7,
- // Instructs DrawStringInt() to render the text using RTL directionality.
+ // Instructs DrawStringRect() to render the text using RTL directionality.
// In most cases, passing this flag is not necessary because information
// about the text directionality is going to be embedded within the string
// in the form of special Unicode characters. However, we don't insert
@@ -83,7 +78,7 @@ class GFX_EXPORT Canvas {
// See FORCE_RTL_DIRECTIONALITY for details.
FORCE_LTR_DIRECTIONALITY = 1 << 9,
- // Instructs DrawStringInt() to not use subpixel rendering. This is useful
+ // Instructs DrawStringRect() to not use subpixel rendering. This is useful
// when rendering text onto a fully- or partially-transparent background
// that will later be blended with another image.
NO_SUBPIXEL_RENDERING = 1 << 10,
@@ -130,13 +125,6 @@ class GFX_EXPORT Canvas {
int* height,
int line_height,
int flags);
- // Obsolete version. Use the above version which takes FontList.
- static void SizeStringInt(const base::string16& text,
- const Font& font,
- int* width,
- int* height,
- int line_height,
- int flags);
// This is same as SizeStringInt except that fractional size is returned.
// See comment in GetStringWidthF for its usage.
@@ -151,8 +139,6 @@ class GFX_EXPORT Canvas {
// |text| with |font_list|.
static int GetStringWidth(const base::string16& text,
const FontList& font_list);
- // Obsolete version. Use the above version which takes FontList.
- static int GetStringWidth(const base::string16& text, const Font& font);
// This is same as GetStringWidth except that fractional width is returned.
// Use this method for the scenario that multiple string widths need to be
@@ -164,7 +150,7 @@ class GFX_EXPORT Canvas {
// Returns the default text alignment to be used when drawing text on a
// Canvas based on the directionality of the system locale language.
- // This function is used by Canvas::DrawStringInt when the text alignment
+ // This function is used by Canvas::DrawStringRect when the text alignment
// is not specified.
//
// This function returns either Canvas::TEXT_ALIGN_LEFT or
@@ -186,16 +172,6 @@ class GFX_EXPORT Canvas {
SkColor halo_color,
const Rect& display_rect,
int flags);
- // Obsolete version. Use the above version which takes FontList.
- void DrawStringWithHalo(const base::string16& text,
- const Font& font,
- SkColor text_color,
- SkColor halo_color,
- int x,
- int y,
- int w,
- int h,
- int flags);
// Extracts an ImageSkiaRep from the contents of this canvas.
ImageSkiaRep ExtractImageRep() const;
@@ -218,13 +194,15 @@ class GFX_EXPORT Canvas {
// call Restore() more times than Save*().
void Restore();
- // Adds |rect| to the current clip. Returns true if the resulting clip is
- // non-empty.
- bool ClipRect(const Rect& rect);
+ // Adds |rect| to the current clip.
+ void ClipRect(const Rect& rect);
+
+ // Adds |path| to the current clip. |do_anti_alias| is true if the clip
+ // should be antialiased.
+ void ClipPath(const SkPath& path, bool do_anti_alias);
- // Adds |path| to the current clip. Returns true if the resulting clip is
- // non-empty.
- bool ClipPath(const SkPath& path);
+ // Returns true if the current clip is empty.
+ bool IsClipEmpty() const;
// Returns the bounds of the current clip (in local coordinates) in the
// |bounds| parameter, and returns true if it is non empty.
@@ -339,6 +317,22 @@ class GFX_EXPORT Canvas {
bool filter,
const SkPaint& paint);
+ // Same as the DrawImageInt functions above. Difference being this does not
+ // do any scaling, i.e. it assumes that the source/destination/image, etc are
+ // in pixels. It does translate the destination rectangle to ensure that the
+ // image is displayed at the correct pixel coordinates.
+ void DrawImageIntInPixel(const ImageSkia& image,
+ int src_x,
+ int src_y,
+ int src_w,
+ int src_h,
+ int dest_x,
+ int dest_y,
+ int dest_w,
+ int dest_h,
+ bool filter,
+ const SkPaint& paint);
+
// Draws an |image| with the top left corner at |x| and |y|, clipped to
// |path|.
// Parameters are specified relative to current canvas scale not in pixels.
@@ -356,18 +350,6 @@ class GFX_EXPORT Canvas {
const FontList& font_list,
SkColor color,
const Rect& display_rect);
- // Obsolete versions. Use the above versions which take FontList.
- void DrawStringInt(const base::string16& text,
- const Font& font,
- SkColor color,
- int x,
- int y,
- int w,
- int h);
- void DrawStringInt(const base::string16& text,
- const Font& font,
- SkColor color,
- const Rect& display_rect);
// Draws text with the specified color, fonts and location. The last argument
// specifies flags for how the text should be rendered. It can be one of
@@ -377,17 +359,8 @@ class GFX_EXPORT Canvas {
SkColor color,
const Rect& display_rect,
int flags);
- // Obsolete version. Use the above version which takes FontList.
- void DrawStringInt(const base::string16& text,
- const Font& font,
- SkColor color,
- int x,
- int y,
- int w,
- int h,
- int flags);
-
- // Similar to above DrawStringInt method but with text shadows support.
+
+ // Similar to above DrawStringRect method but with text shadows support.
// Currently it's only implemented for canvas skia. Specifying a 0 line_height
// will cause the default height to be used.
void DrawStringRectWithShadows(const base::string16& text,
@@ -397,14 +370,6 @@ class GFX_EXPORT Canvas {
int line_height,
int flags,
const ShadowValues& shadows);
- // Obsolete version. Use the above version which takes FontList.
- void DrawStringWithShadows(const base::string16& text,
- const Font& font,
- SkColor color,
- const Rect& text_bounds,
- int line_height,
- int flags,
- const ShadowValues& shadows);
// Draws a dotted gray rectangle used for focus purposes.
void DrawFocusRect(const Rect& rect);
@@ -449,20 +414,12 @@ class GFX_EXPORT Canvas {
// Apply transformation on the canvas.
void Transform(const Transform& transform);
- // Draws the given string with the beginning or the end using a fade gradient.
- void DrawFadeTruncatingStringRect(
- const base::string16& text,
- TruncateFadeMode truncate_mode,
- const FontList& font_list,
- SkColor color,
- const Rect& display_rect);
- void DrawFadeTruncatingStringRectWithFlags(
- const base::string16& text,
- TruncateFadeMode truncate_mode,
- const FontList& font_list,
- SkColor color,
- const Rect& display_rect,
- int flags);
+ // Draws the given string with a fade gradient at the end.
+ void DrawFadedString(const base::string16& text,
+ const FontList& font_list,
+ SkColor color,
+ const Rect& display_rect,
+ int flags);
skia::PlatformCanvas* platform_canvas() const { return owned_canvas_.get(); }
SkCanvas* sk_canvas() const { return canvas_; }
@@ -475,16 +432,22 @@ class GFX_EXPORT Canvas {
bool IntersectsClipRectInt(int x, int y, int w, int h);
bool IntersectsClipRect(const Rect& rect);
- // Returns the image rep which best matches the canvas |image_scale_|.
- // Returns a null image rep if |image| contains no image reps.
- // Builds mip map for returned image rep if necessary.
- //
- // An optional additional user defined scale can be provided.
- const ImageSkiaRep& GetImageRepToPaint(const ImageSkia& image) const;
- const ImageSkiaRep& GetImageRepToPaint(
- const ImageSkia& image,
- float user_defined_scale_factor_x,
- float user_defined_scale_factor_y) const;
+ // Helper for the DrawImageInt functions declared above. The |pixel|
+ // parameter if true indicates that the bounds and the image are to
+ // be assumed to be in pixels, i.e. no scaling needs to be performed.
+ void DrawImageIntHelper(const ImageSkia& image,
+ int src_x,
+ int src_y,
+ int src_w,
+ int src_h,
+ int dest_x,
+ int dest_y,
+ int dest_w,
+ int dest_h,
+ bool filter,
+ const SkPaint& paint,
+ float image_scale,
+ bool pixel);
// The device scale factor at which drawing on this canvas occurs.
// An additional scale can be applied via Canvas::Scale(). However,
diff --git a/chromium/ui/gfx/canvas_paint_gtk.cc b/chromium/ui/gfx/canvas_paint_gtk.cc
deleted file mode 100644
index aef6fc982e3..00000000000
--- a/chromium/ui/gfx/canvas_paint_gtk.cc
+++ /dev/null
@@ -1,107 +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/basictypes.h"
-#include "base/compiler_specific.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/canvas_skia_paint.h"
-#include "ui/gfx/rect.h"
-
-namespace gfx {
-
-// CanvasSkiaPaint
-
-CanvasSkiaPaint::CanvasSkiaPaint(GdkEventExpose* event)
- : context_(NULL),
- window_(event->window),
- region_(gdk_region_copy(event->region)),
- composite_alpha_(false) {
- Init(true);
-}
-
-CanvasSkiaPaint::CanvasSkiaPaint(GdkEventExpose* event, bool opaque)
- : context_(NULL),
- window_(event->window),
- region_(gdk_region_copy(event->region)),
- composite_alpha_(false) {
- Init(opaque);
-}
-
-CanvasSkiaPaint::~CanvasSkiaPaint() {
- if (!is_empty()) {
- platform_canvas()->restoreToCount(1);
-
- // Blit the dirty rect to the window.
- CHECK(window_);
- cairo_t* cr = gdk_cairo_create(window_);
- CHECK(cr);
- if (composite_alpha_)
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- cairo_surface_t* source_surface = cairo_get_target(context_);
- CHECK(source_surface);
- // Flush cairo's cache of the surface.
- cairo_surface_mark_dirty(source_surface);
- GdkRectangle bounds = rectangle();
- cairo_set_source_surface(cr, source_surface, bounds.x, bounds.y);
- gdk_cairo_region(cr, region_);
- cairo_fill(cr);
- cairo_destroy(cr);
- }
-
- gdk_region_destroy(region_);
-}
-
-void CanvasSkiaPaint::Init(bool opaque) {
- GdkRectangle bounds = rectangle();
- RecreateBackingCanvas(Size(bounds.width, bounds.height), 1.0f, opaque);
-
- skia::PlatformCanvas* canvas = platform_canvas();
-
- // Need to translate so that the dirty region appears at the origin of the
- // surface.
- canvas->translate(-SkIntToScalar(bounds.x), -SkIntToScalar(bounds.y));
-
- context_ = skia::BeginPlatformPaint(canvas);
-}
-
-// CanvasSkiaPaintCairo
-
-CanvasSkiaPaintCairo::CanvasSkiaPaintCairo(cairo_t* cairo,
- Size size,
- bool opaque)
- : context_(NULL),
- dest_(cairo),
- size_(size),
- composite_alpha_(false) {
- CHECK(dest_);
- Init(opaque);
-}
-
-CanvasSkiaPaintCairo::~CanvasSkiaPaintCairo() {
- if (!is_empty()) {
- platform_canvas()->restoreToCount(1);
-
- // Blit the dirty rect to the window.
- if (composite_alpha_)
- cairo_set_operator(dest_, CAIRO_OPERATOR_SOURCE);
- cairo_surface_t* source_surface = cairo_get_target(context_);
- CHECK(source_surface);
- // Flush cairo's cache of the surface.
- cairo_surface_mark_dirty(source_surface);
- cairo_set_source_surface(dest_, source_surface, 0, 0);
- GdkRectangle bounds = {0, 0, size_.width(), size_.height()};
- gdk_cairo_rectangle(dest_, &bounds);
- cairo_fill(dest_);
- }
-}
-
-void CanvasSkiaPaintCairo::Init(bool opaque) {
- RecreateBackingCanvas(size_, 1.0f, opaque);
-
- context_ = skia::BeginPlatformPaint(platform_canvas());
-}
-
-} // namespace gfx
-
-
diff --git a/chromium/ui/gfx/canvas_paint_gtk.h b/chromium/ui/gfx/canvas_paint_gtk.h
deleted file mode 100644
index 487db79f47a..00000000000
--- a/chromium/ui/gfx/canvas_paint_gtk.h
+++ /dev/null
@@ -1,102 +0,0 @@
-
-// Copyright (c) 2011 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_LINUX_H_
-#define UI_GFX_CANVAS_PAINT_LINUX_H_
-
-#include "base/logging.h"
-#include "skia/ext/platform_canvas.h"
-#include "ui/gfx/canvas.h"
-#include <gdk/gdk.h>
-
-namespace gfx {
-
-// A class designed to translate skia painting into a region in a GdkWindow.
-// On construction, it will set up a context for painting into, and on
-// destruction, it will commit it to the GdkWindow.
-// 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(GdkEventExpose* event);
- CanvasSkiaPaint(GdkEventExpose* event, bool opaque);
- virtual ~CanvasSkiaPaint();
-
- // Sets whether the bitmap is composited in such a way that the alpha channel
- // is honored. This is only useful if you've enabled an RGBA colormap on the
- // widget. The default is false.
- 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 gdk_region_empty(region_);
- }
-
- GdkRectangle rectangle() const {
- GdkRectangle bounds;
- gdk_region_get_clipbox(region_, &bounds);
- return bounds;
- }
-
- private:
- void Init(bool opaque);
-
- cairo_t* context_;
- GdkWindow* window_;
- GdkRegion* region_;
- // See description above setter.
- bool composite_alpha_;
-
- // Disallow copy and assign.
- CanvasSkiaPaint(const CanvasSkiaPaint&);
- CanvasSkiaPaint& operator=(const CanvasSkiaPaint&);
-};
-
-// A class designed to translate skia painting into a region in a Cairo context.
-// On construction, it will set up a context for painting into, and on
-// destruction, it will commit it to the Cairo context. If there are any
-// transformations applied to the Cairo context, they will affect the drawing.
-class GFX_EXPORT CanvasSkiaPaintCairo : public Canvas {
- public:
- CanvasSkiaPaintCairo(cairo_t* cairo, Size size, bool opaque);
- virtual ~CanvasSkiaPaintCairo();
-
- // Sets whether the bitmap is composited in such a way that the alpha channel
- // is honored. This is only useful if you've enabled an RGBA colormap on the
- // widget. The default is false.
- void set_composite_alpha(bool composite_alpha) {
- composite_alpha_ = composite_alpha;
- }
-
- // Returns true if size of the drawing region is empty. The caller should call
- // this function to determine if anything needs painting.
- bool is_empty() const {
- return size_.IsEmpty();
- }
-
- Size size() const {
- return size_;
- }
-
- private:
- void Init(bool opaque);
-
- cairo_t* context_;
- cairo_t* dest_;
- Size size_;
- // See description above setter.
- bool composite_alpha_;
-
- // Disallow copy and assign.
- CanvasSkiaPaintCairo(const CanvasSkiaPaintCairo&);
- CanvasSkiaPaintCairo& operator=(const CanvasSkiaPaintCairo&);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_CANVAS_PAINT_LINUX_H_
diff --git a/chromium/ui/gfx/canvas_skia.cc b/chromium/ui/gfx/canvas_skia.cc
index 1ad60ba2b04..8d1311faf39 100644
--- a/chromium/ui/gfx/canvas_skia.cc
+++ b/chromium/ui/gfx/canvas_skia.cc
@@ -84,7 +84,7 @@ bool PixelShouldGetHalo(const SkBitmap& bitmap,
}
// Strips accelerator character prefixes in |text| if needed, based on |flags|.
-// Returns a range in |text| to underline or gfx::Range::InvalidRange() if
+// Returns a range in |text| to underline or Range::InvalidRange() if
// underlining is not needed.
Range StripAcceleratorChars(int flags, base::string16* text) {
if (flags & (Canvas::SHOW_PREFIX | Canvas::HIDE_PREFIX)) {
@@ -105,7 +105,7 @@ void ElideTextAndAdjustRange(const FontList& font_list,
Range* range) {
const base::char16 start_char =
(range->IsValid() ? text->at(range->start()) : 0);
- *text = gfx::ElideText(*text, font_list, width, gfx::ELIDE_AT_END);
+ *text = ElideText(*text, font_list, width, ELIDE_TAIL);
if (!range->IsValid())
return;
if (range->start() >= text->length() ||
@@ -171,17 +171,16 @@ void Canvas::SizeStringFloat(const base::string16& text,
#endif
if ((flags & MULTI_LINE) && *width != 0) {
- gfx::WordWrapBehavior wrap_behavior = gfx::TRUNCATE_LONG_WORDS;
+ WordWrapBehavior wrap_behavior = TRUNCATE_LONG_WORDS;
if (flags & CHARACTER_BREAK)
- wrap_behavior = gfx::WRAP_LONG_WORDS;
+ wrap_behavior = WRAP_LONG_WORDS;
else if (!(flags & NO_ELLIPSIS))
- wrap_behavior = gfx::ELIDE_LONG_WORDS;
+ wrap_behavior = ELIDE_LONG_WORDS;
Rect rect(*width, INT_MAX);
std::vector<base::string16> strings;
- gfx::ElideRectangleText(adjusted_text, font_list,
- rect.width(), rect.height(),
- wrap_behavior, &strings);
+ ElideRectangleText(adjusted_text, font_list, rect.width(), rect.height(),
+ wrap_behavior, &strings);
scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
UpdateRenderText(rect, base::string16(), font_list, flags, 0,
render_text.get());
@@ -230,7 +229,7 @@ void Canvas::DrawStringRectWithShadows(const base::string16& text,
Rect clip_rect(text_bounds);
clip_rect.Inset(ShadowValue::GetMargin(shadows));
- canvas_->save(SkCanvas::kClip_SaveFlag);
+ canvas_->save();
ClipRect(clip_rect);
Rect rect(text_bounds);
@@ -241,21 +240,18 @@ void Canvas::DrawStringRectWithShadows(const base::string16& text,
#endif
scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
- render_text->SetTextShadows(shadows);
+ render_text->set_shadows(shadows);
if (flags & MULTI_LINE) {
- gfx::WordWrapBehavior wrap_behavior = gfx::IGNORE_LONG_WORDS;
+ WordWrapBehavior wrap_behavior = IGNORE_LONG_WORDS;
if (flags & CHARACTER_BREAK)
- wrap_behavior = gfx::WRAP_LONG_WORDS;
+ wrap_behavior = WRAP_LONG_WORDS;
else if (!(flags & NO_ELLIPSIS))
- wrap_behavior = gfx::ELIDE_LONG_WORDS;
+ wrap_behavior = ELIDE_LONG_WORDS;
std::vector<base::string16> strings;
- gfx::ElideRectangleText(adjusted_text,
- font_list,
- text_bounds.width(), text_bounds.height(),
- wrap_behavior,
- &strings);
+ ElideRectangleText(adjusted_text, font_list, text_bounds.width(),
+ text_bounds.height(), wrap_behavior, &strings);
for (size_t i = 0; i < strings.size(); i++) {
Range range = StripAcceleratorChars(flags, &strings[i]);
@@ -294,16 +290,14 @@ void Canvas::DrawStringRectWithShadows(const base::string16& text,
if (elide_text) {
render_text->SetText(adjusted_text);
if (render_text->GetTextDirection() == base::i18n::LEFT_TO_RIGHT) {
- render_text->set_fade_tail(true);
+ render_text->SetElideBehavior(FADE_TAIL);
elide_text = false;
}
}
#endif
if (elide_text) {
- ElideTextAndAdjustRange(font_list,
- text_bounds.width(),
- &adjusted_text,
+ ElideTextAndAdjustRange(font_list, text_bounds.width(), &adjusted_text,
&range);
}
@@ -311,7 +305,6 @@ void Canvas::DrawStringRectWithShadows(const base::string16& text,
render_text.get());
const int text_height = render_text->GetStringSize().height();
- // Center the text vertically.
rect += Vector2d(0, (text_bounds.height() - text_height) / 2);
rect.set_height(text_height);
render_text->SetDisplayRect(rect);
@@ -371,60 +364,44 @@ void Canvas::DrawStringRectWithHalo(const base::string16& text,
DrawImageInt(text_image, display_rect.x() - 1, display_rect.y() - 1);
}
-void Canvas::DrawFadeTruncatingStringRect(
- const base::string16& text,
- TruncateFadeMode truncate_mode,
- const FontList& font_list,
- SkColor color,
- const Rect& display_rect) {
- DrawFadeTruncatingStringRectWithFlags(
- text, truncate_mode, font_list, color, display_rect, NO_ELLIPSIS);
-}
-
-void Canvas::DrawFadeTruncatingStringRectWithFlags(
- const base::string16& text,
- TruncateFadeMode truncate_mode,
- const FontList& font_list,
- SkColor color,
- const Rect& display_rect,
- int flags) {
+void Canvas::DrawFadedString(const base::string16& text,
+ const FontList& font_list,
+ SkColor color,
+ const Rect& display_rect,
+ int flags) {
// If the whole string fits in the destination then just draw it directly.
if (GetStringWidth(text, font_list) <= display_rect.width()) {
DrawStringRectWithFlags(text, font_list, color, display_rect, flags);
return;
}
- scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
- const bool is_rtl = base::i18n::GetFirstStrongCharacterDirection(text) ==
- base::i18n::RIGHT_TO_LEFT;
-
- switch (truncate_mode) {
- case TruncateFadeTail:
- render_text->set_fade_tail(true);
- if (is_rtl)
- flags |= TEXT_ALIGN_RIGHT;
- break;
- case TruncateFadeHead:
- render_text->set_fade_head(true);
- if (!is_rtl)
- flags |= TEXT_ALIGN_RIGHT;
- break;
- }
-
- // Default to left alignment unless right alignment was chosen above.
- if (!(flags & TEXT_ALIGN_RIGHT))
+ // Align with forced content directionality, overriding alignment flags.
+ if (flags & FORCE_RTL_DIRECTIONALITY) {
+ flags &= ~(TEXT_ALIGN_CENTER | TEXT_ALIGN_LEFT);
+ flags |= TEXT_ALIGN_RIGHT;
+ } else if (flags & FORCE_LTR_DIRECTIONALITY) {
+ flags &= ~(TEXT_ALIGN_CENTER | TEXT_ALIGN_RIGHT);
flags |= TEXT_ALIGN_LEFT;
+ } else if (!(flags & TEXT_ALIGN_LEFT) && !(flags & TEXT_ALIGN_RIGHT)) {
+ // Also align with content directionality instead of fading both ends.
+ flags &= ~TEXT_ALIGN_CENTER;
+ const bool is_rtl = base::i18n::GetFirstStrongCharacterDirection(text) ==
+ base::i18n::RIGHT_TO_LEFT;
+ flags |= is_rtl ? TEXT_ALIGN_RIGHT : TEXT_ALIGN_LEFT;
+ }
+ flags |= NO_ELLIPSIS;
+ scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
Rect rect = display_rect;
UpdateRenderText(rect, text, font_list, flags, color, render_text.get());
+ render_text->SetElideBehavior(FADE_TAIL);
const int line_height = render_text->GetStringSize().height();
- // Center the text vertically.
rect += Vector2d(0, (display_rect.height() - line_height) / 2);
rect.set_height(line_height);
render_text->SetDisplayRect(rect);
- canvas_->save(SkCanvas::kClip_SaveFlag);
+ canvas_->save();
ClipRect(display_rect);
render_text->Draw(this);
canvas_->restore();
diff --git a/chromium/ui/gfx/canvas_skia_paint.h b/chromium/ui/gfx/canvas_skia_paint.h
index 3f21f5cc410..e9e22fff44e 100644
--- a/chromium/ui/gfx/canvas_skia_paint.h
+++ b/chromium/ui/gfx/canvas_skia_paint.h
@@ -12,12 +12,8 @@
#include "ui/gfx/canvas_paint_win.h"
#elif defined(__APPLE__)
#include "ui/gfx/canvas_paint_mac.h"
-#elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun)
-#if defined(TOOLKIT_GTK)
-#include "ui/gfx/canvas_paint_gtk.h"
#else
#error "No canvas paint for this platform"
#endif
-#endif
#endif // UI_GFX_CANVAS_SKIA_PAINT_H_
diff --git a/chromium/ui/gfx/canvas_unittest.cc b/chromium/ui/gfx/canvas_unittest.cc
index 21b9f51e57e..806e8f0e7a5 100644
--- a/chromium/ui/gfx/canvas_unittest.cc
+++ b/chromium/ui/gfx/canvas_unittest.cc
@@ -2,32 +2,34 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "ui/gfx/canvas.h"
+
#include <limits>
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
namespace gfx {
class CanvasTest : public testing::Test {
protected:
int GetStringWidth(const char *text) {
- return Canvas::GetStringWidth(UTF8ToUTF16(text), font_);
+ return Canvas::GetStringWidth(base::UTF8ToUTF16(text), font_list_);
}
gfx::Size SizeStringInt(const char *text, int width, int line_height) {
- base::string16 text16 = UTF8ToUTF16(text);
+ base::string16 text16 = base::UTF8ToUTF16(text);
int height = 0;
int flags =
- (text16.find('\n') != base::string16::npos) ? Canvas::MULTI_LINE : 0;
- Canvas::SizeStringInt(text16, font_, &width, &height, line_height, flags);
+ (text16.find('\n') != base::string16::npos) ? Canvas::MULTI_LINE : 0;
+ Canvas::SizeStringInt(text16, font_list_, &width, &height, line_height,
+ flags);
return gfx::Size(width, height);
}
private:
- gfx::Font font_;
+ FontList font_list_;
};
TEST_F(CanvasTest, StringWidth) {
diff --git a/chromium/ui/gfx/codec/png_codec.cc b/chromium/ui/gfx/codec/png_codec.cc
index b3f4345343f..d098eb4ee18 100644
--- a/chromium/ui/gfx/codec/png_codec.cc
+++ b/chromium/ui/gfx/codec/png_codec.cc
@@ -678,15 +678,29 @@ bool EncodeWithCompressionLevel(const unsigned char* input,
break;
case PNGCodec::FORMAT_SkBitmap:
- input_color_components = 4;
- if (discard_transparency) {
- output_color_components = 3;
- png_output_color_type = PNG_COLOR_TYPE_RGB;
- converter = ConvertSkiatoRGB;
+ // Compare row_byte_width and size.width() to detect the format of
+ // SkBitmap. kA8_Config (1bpp) and kARGB_8888_Config (4bpp) are the two
+ // supported formats.
+ if (row_byte_width < 4 * size.width()) {
+ // Not 4bpp, so must be 1bpp.
+ // Ignore discard_transparency - it doesn't make sense in this context,
+ // since alpha is the only thing we have and it needs to be used for
+ // color intensity.
+ input_color_components = 1;
+ output_color_components = 1;
+ png_output_color_type = PNG_COLOR_TYPE_GRAY;
+ // |converter| is left as null
} else {
- output_color_components = 4;
- png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
- converter = ConvertSkiatoRGBA;
+ input_color_components = 4;
+ if (discard_transparency) {
+ output_color_components = 3;
+ png_output_color_type = PNG_COLOR_TYPE_RGB;
+ converter = ConvertSkiatoRGB;
+ } else {
+ output_color_components = 4;
+ png_output_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+ converter = ConvertSkiatoRGBA;
+ }
}
break;
@@ -719,12 +733,38 @@ bool EncodeWithCompressionLevel(const unsigned char* input,
return success;
}
+bool InternalEncodeSkBitmap(const SkBitmap& input,
+ bool discard_transparency,
+ int compression_level,
+ std::vector<unsigned char>* output) {
+ if (input.empty() || input.isNull())
+ return false;
+ int bpp = input.bytesPerPixel();
+ DCHECK(bpp == 1 || bpp == 4); // We support kA8_Config and kARGB_8888_Config.
+
+ SkAutoLockPixels lock_input(input);
+ unsigned char* inputAddr = bpp == 1 ?
+ reinterpret_cast<unsigned char*>(input.getAddr8(0, 0)) :
+ reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)); // bpp = 4
+ return EncodeWithCompressionLevel(
+ inputAddr,
+ PNGCodec::FORMAT_SkBitmap,
+ Size(input.width(), input.height()),
+ static_cast<int>(input.rowBytes()),
+ discard_transparency,
+ std::vector<PNGCodec::Comment>(),
+ compression_level,
+ output);
+}
+
} // namespace
// static
-bool PNGCodec::Encode(const unsigned char* input, ColorFormat format,
- const Size& size, int row_byte_width,
+bool PNGCodec::Encode(const unsigned char* input,
+ ColorFormat format,
+ const Size& size,
+ int row_byte_width,
bool discard_transparency,
const std::vector<Comment>& comments,
std::vector<unsigned char>* output) {
@@ -742,37 +782,29 @@ bool PNGCodec::Encode(const unsigned char* input, ColorFormat format,
bool PNGCodec::EncodeBGRASkBitmap(const SkBitmap& input,
bool discard_transparency,
std::vector<unsigned char>* output) {
- static const int bbp = 4;
-
- if (input.empty())
- return false;
- DCHECK_EQ(input.bytesPerPixel(), bbp);
- DCHECK_GE(static_cast<int>(input.rowBytes()), input.width() * bbp);
+ return InternalEncodeSkBitmap(input,
+ discard_transparency,
+ Z_DEFAULT_COMPRESSION,
+ output);
+}
- SkAutoLockPixels lock_input(input);
- return Encode(reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)),
- FORMAT_SkBitmap, Size(input.width(), input.height()),
- static_cast<int>(input.rowBytes()), discard_transparency,
- std::vector<Comment>(), output);
+// static
+bool PNGCodec::EncodeA8SkBitmap(const SkBitmap& input,
+ std::vector<unsigned char>* output) {
+ return InternalEncodeSkBitmap(input,
+ false,
+ Z_DEFAULT_COMPRESSION,
+ output);
}
// static
bool PNGCodec::FastEncodeBGRASkBitmap(const SkBitmap& input,
bool discard_transparency,
std::vector<unsigned char>* output) {
- static const int bbp = 4;
-
- if (input.empty())
- return false;
- DCHECK_EQ(input.bytesPerPixel(), bbp);
- DCHECK_GE(static_cast<int>(input.rowBytes()), input.width() * bbp);
-
- SkAutoLockPixels lock_input(input);
- return EncodeWithCompressionLevel(
- reinterpret_cast<unsigned char*>(input.getAddr32(0, 0)),
- FORMAT_SkBitmap, Size(input.width(), input.height()),
- static_cast<int>(input.rowBytes()), discard_transparency,
- std::vector<Comment>(), Z_BEST_SPEED, output);
+ return InternalEncodeSkBitmap(input,
+ discard_transparency,
+ Z_BEST_SPEED,
+ output);
}
PNGCodec::Comment::Comment(const std::string& k, const std::string& t)
diff --git a/chromium/ui/gfx/codec/png_codec.h b/chromium/ui/gfx/codec/png_codec.h
index abb3eaab32c..5f849c462fc 100644
--- a/chromium/ui/gfx/codec/png_codec.h
+++ b/chromium/ui/gfx/codec/png_codec.h
@@ -37,8 +37,10 @@ class GFX_EXPORT PNGCodec {
// This is the default Windows DIB order.
FORMAT_BGRA,
- // 4 bytes per pixel, in pre-multiplied kARGB_8888_Config format. For use
- // with directly writing to a skia bitmap.
+ // SkBitmap format. For Encode() kARGB_8888_Config (4 bytes per pixel) and
+ // kA8_Config (1 byte per pixel) formats are supported. kA8_Config gets
+ // encoded into a grayscale PNG treating alpha as the color intensity.
+ // For Decode() kARGB_8888_Config is always used.
FORMAT_SkBitmap
};
@@ -77,9 +79,10 @@ class GFX_EXPORT PNGCodec {
std::vector<unsigned char>* output);
// Call PNGCodec::Encode on the supplied SkBitmap |input|, which is assumed
- // to be BGRA, 32 bits per pixel. The params |discard_transparency| and
- // |output| are passed directly to Encode; refer to Encode for more
- // information. During the call, an SkAutoLockPixels lock is held on |input|.
+ // to be kARGB_8888_Config, 32 bits per pixel. The params
+ // |discard_transparency| and |output| are passed directly to Encode; refer to
+ // Encode for more information. During the call, an SkAutoLockPixels lock
+ // is held on |input|.
static bool EncodeBGRASkBitmap(const SkBitmap& input,
bool discard_transparency,
std::vector<unsigned char>* output);
@@ -91,6 +94,14 @@ class GFX_EXPORT PNGCodec {
bool discard_transparency,
std::vector<unsigned char>* output);
+ // Call PNGCodec::Encode on the supplied SkBitmap |input|, which is assumed
+ // to be kA8_Config, 8 bits per pixel. The bitmap is encoded as a grayscale
+ // PNG with alpha used for color intensity. The |output| param is passed
+ // directly to Encode; refer to Encode for more information. During the call,
+ // an SkAutoLockPixels lock is held on |input|.
+ static bool EncodeA8SkBitmap(const SkBitmap& input,
+ std::vector<unsigned char>* output);
+
// Decodes the PNG data contained in input of length input_size. The
// decoded data will be placed in *output with the dimensions in *w and *h
// on success (returns true). This data will be written in the 'format'
diff --git a/chromium/ui/gfx/codec/png_codec_unittest.cc b/chromium/ui/gfx/codec/png_codec_unittest.cc
index f1654d9d363..37816807ba9 100644
--- a/chromium/ui/gfx/codec/png_codec_unittest.cc
+++ b/chromium/ui/gfx/codec/png_codec_unittest.cc
@@ -249,14 +249,29 @@ bool NonAlphaColorsClose(uint32_t a, uint32_t b) {
abs(static_cast<int>(SkColorGetR(a) - SkColorGetR(b))) < 2;
}
-void MakeTestSkBitmap(int w, int h, SkBitmap* bmp) {
+// Returns true if the BGRA 32-bit SkColor specified by |a| is equivalent to the
+// 8-bit Gray color specified by |b|.
+bool BGRAGrayEqualsA8Gray(uint32_t a, uint8_t b) {
+ return SkColorGetB(a) == b && SkColorGetG(a) == b &&
+ SkColorGetR(a) == b && SkColorGetA(a) == 255;
+}
+
+void MakeTestBGRASkBitmap(int w, int h, SkBitmap* bmp) {
bmp->setConfig(SkBitmap::kARGB_8888_Config, w, h);
bmp->allocPixels();
uint32_t* src_data = bmp->getAddr32(0, 0);
- for (int i = 0; i < w * h; i++) {
+ for (int i = 0; i < w * h; i++)
src_data[i] = SkPreMultiplyARGB(i % 255, i % 250, i % 245, i % 240);
- }
+}
+
+void MakeTestA8SkBitmap(int w, int h, SkBitmap* bmp) {
+ bmp->setConfig(SkBitmap::kA8_Config, w, h);
+ bmp->allocPixels();
+
+ uint8_t* src_data = bmp->getAddr8(0, 0);
+ for (int i = 0; i < w * h; i++)
+ src_data[i] = i % 255;
}
TEST(PNGCodec, EncodeDecodeRGB) {
@@ -1017,7 +1032,7 @@ TEST(PNGCodec, EncodeBGRASkBitmap) {
const int w = 20, h = 20;
SkBitmap original_bitmap;
- MakeTestSkBitmap(w, h, &original_bitmap);
+ MakeTestBGRASkBitmap(w, h, &original_bitmap);
// Encode the bitmap.
std::vector<unsigned char> encoded;
@@ -1040,11 +1055,35 @@ TEST(PNGCodec, EncodeBGRASkBitmap) {
}
}
+TEST(PNGCodec, EncodeA8SkBitmap) {
+ const int w = 20, h = 20;
+
+ SkBitmap original_bitmap;
+ MakeTestA8SkBitmap(w, h, &original_bitmap);
+
+ // Encode the bitmap.
+ std::vector<unsigned char> encoded;
+ EXPECT_TRUE(PNGCodec::EncodeA8SkBitmap(original_bitmap, &encoded));
+
+ // Decode the encoded string.
+ SkBitmap decoded_bitmap;
+ EXPECT_TRUE(PNGCodec::Decode(&encoded.front(), encoded.size(),
+ &decoded_bitmap));
+
+ for (int x = 0; x < w; x++) {
+ for (int y = 0; y < h; y++) {
+ uint8_t original_pixel = *original_bitmap.getAddr8(x, y);
+ uint32_t decoded_pixel = *decoded_bitmap.getAddr32(x, y);
+ EXPECT_TRUE(BGRAGrayEqualsA8Gray(decoded_pixel, original_pixel));
+ }
+ }
+}
+
TEST(PNGCodec, EncodeBGRASkBitmapDiscardTransparency) {
const int w = 20, h = 20;
SkBitmap original_bitmap;
- MakeTestSkBitmap(w, h, &original_bitmap);
+ MakeTestBGRASkBitmap(w, h, &original_bitmap);
// Encode the bitmap.
std::vector<unsigned char> encoded;
@@ -1121,7 +1160,7 @@ TEST(PNGCodec, EncodeDecodeWithVaryingCompressionLevels) {
// create an image with known values, a must be opaque because it will be
// lost during encoding
SkBitmap original_bitmap;
- MakeTestSkBitmap(w, h, &original_bitmap);
+ MakeTestBGRASkBitmap(w, h, &original_bitmap);
// encode
std::vector<unsigned char> encoded_normal;
diff --git a/chromium/ui/gfx/color_analysis.cc b/chromium/ui/gfx/color_analysis.cc
index f8987cfb546..5cae9b6d4cc 100644
--- a/chromium/ui/gfx/color_analysis.cc
+++ b/chromium/ui/gfx/color_analysis.cc
@@ -13,14 +13,17 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkUnPreMultiply.h"
#include "ui/gfx/codec/png_codec.h"
+#include "ui/gfx/color_utils.h"
+namespace color_utils {
namespace {
// RGBA KMean Constants
const uint32_t kNumberOfClusters = 4;
const int kNumberOfIterations = 50;
-const uint32_t kMaxBrightness = 665;
-const uint32_t kMinDarkness = 100;
+
+const HSL kDefaultLowerHSLBound = {-1, -1, 0.15};
+const HSL kDefaultUpperHSLBound = {-1, -1, 0.85};
// Background Color Modification Constants
const SkColor kDefaultBgColor = SK_ColorWHITE;
@@ -139,8 +142,6 @@ void UnPreMultiply(const SkBitmap& bitmap, uint32_t* buffer, int buffer_size) {
} // namespace
-namespace color_utils {
-
KMeanImageSampler::KMeanImageSampler() {
}
@@ -214,8 +215,8 @@ SkColor FindClosestColor(const uint8_t* image,
SkColor CalculateKMeanColorOfBuffer(uint8_t* decoded_data,
int img_width,
int img_height,
- uint32_t darkness_limit,
- uint32_t brightness_limit,
+ const HSL& lower_bound,
+ const HSL& upper_bound,
KMeanImageSampler* sampler) {
SkColor color = kDefaultBgColor;
if (img_width > 0 && img_height > 0) {
@@ -331,21 +332,19 @@ SkColor CalculateKMeanColorOfBuffer(uint8_t* decoded_data,
cluster != clusters.end(); ++cluster) {
uint8_t r, g, b;
cluster->GetCentroid(&r, &g, &b);
- // Sum the RGB components to determine if the color is too bright or too
- // dark.
- // TODO (dtrainor): Look into using HSV here instead. This approximation
- // might be fine though.
- uint32_t summed_color = r + g + b;
- if (summed_color < brightness_limit && summed_color > darkness_limit) {
+ SkColor current_color = SkColorSetARGB(SK_AlphaOPAQUE, r, g, b);
+ HSL hsl;
+ SkColorToHSL(current_color, &hsl);
+ if (IsWithinHSLRange(hsl, lower_bound, upper_bound)) {
// If we found a valid color just set it and break. We don't want to
// check the other ones.
- color = SkColorSetARGB(0xFF, r, g, b);
+ color = current_color;
break;
} else if (cluster == clusters.begin()) {
// We haven't found a valid color, but we are at the first color so
// set the color anyway to make sure we at least have a value here.
- color = SkColorSetARGB(0xFF, r, g, b);
+ color = current_color;
}
}
}
@@ -356,16 +355,15 @@ SkColor CalculateKMeanColorOfBuffer(uint8_t* decoded_data,
}
SkColor CalculateKMeanColorOfPNG(scoped_refptr<base::RefCountedMemory> png,
- uint32_t darkness_limit,
- uint32_t brightness_limit,
+ const HSL& lower_bound,
+ const HSL& upper_bound,
KMeanImageSampler* sampler) {
int img_width = 0;
int img_height = 0;
std::vector<uint8_t> decoded_data;
SkColor color = kDefaultBgColor;
- if (png.get() &&
- png->size() &&
+ if (png.get() && png->size() &&
gfx::PNGCodec::Decode(png->front(),
png->size(),
gfx::PNGCodec::FORMAT_BGRA,
@@ -375,14 +373,23 @@ SkColor CalculateKMeanColorOfPNG(scoped_refptr<base::RefCountedMemory> png,
return CalculateKMeanColorOfBuffer(&decoded_data[0],
img_width,
img_height,
- darkness_limit,
- brightness_limit,
+ lower_bound,
+ upper_bound,
sampler);
}
return color;
}
-SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap) {
+SkColor CalculateKMeanColorOfPNG(scoped_refptr<base::RefCountedMemory> png) {
+ GridSampler sampler;
+ return CalculateKMeanColorOfPNG(
+ png, kDefaultLowerHSLBound, kDefaultUpperHSLBound, &sampler);
+}
+
+SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap,
+ const HSL& lower_bound,
+ const HSL& upper_bound,
+ KMeanImageSampler* sampler) {
// SkBitmap uses pre-multiplied alpha but the KMean clustering function
// above uses non-pre-multiplied alpha. Transform the bitmap before we
// analyze it because the function reads each pixel multiple times.
@@ -390,15 +397,18 @@ SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap) {
scoped_ptr<uint32_t[]> image(new uint32_t[pixel_count]);
UnPreMultiply(bitmap, image.get(), pixel_count);
+ return CalculateKMeanColorOfBuffer(reinterpret_cast<uint8_t*>(image.get()),
+ bitmap.width(),
+ bitmap.height(),
+ lower_bound,
+ upper_bound,
+ sampler);
+}
+
+SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap) {
GridSampler sampler;
- SkColor color = CalculateKMeanColorOfBuffer(
- reinterpret_cast<uint8_t*>(image.get()),
- bitmap.width(),
- bitmap.height(),
- kMinDarkness,
- kMaxBrightness,
- &sampler);
- return color;
+ return CalculateKMeanColorOfBitmap(
+ bitmap, kDefaultLowerHSLBound, kDefaultUpperHSLBound, &sampler);
}
gfx::Matrix3F ComputeColorCovariance(const SkBitmap& bitmap) {
@@ -409,7 +419,7 @@ gfx::Matrix3F ComputeColorCovariance(const SkBitmap& bitmap) {
return covariance;
// Assume ARGB_8888 format.
- DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(bitmap.colorType() == kPMColor_SkColorType);
int64_t r_sum = 0;
int64_t g_sum = 0;
@@ -478,8 +488,8 @@ bool ApplyColorReduction(const SkBitmap& source_bitmap,
DCHECK(source_bitmap.getPixels());
DCHECK(target_bitmap->getPixels());
- DCHECK_EQ(SkBitmap::kARGB_8888_Config, source_bitmap.config());
- DCHECK_EQ(SkBitmap::kA8_Config, target_bitmap->config());
+ DCHECK_EQ(kPMColor_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());
diff --git a/chromium/ui/gfx/color_analysis.h b/chromium/ui/gfx/color_analysis.h
index dcbfabc9d77..dd273bc11e4 100644
--- a/chromium/ui/gfx/color_analysis.h
+++ b/chromium/ui/gfx/color_analysis.h
@@ -17,6 +17,8 @@ class SkBitmap;
namespace color_utils {
+struct HSL;
+
// This class exposes the sampling method to the caller, which allows
// stubbing out for things like unit tests. Might be useful to pass more
// arguments into the GetSample method in the future (such as which
@@ -52,14 +54,13 @@ class GFX_EXPORT GridSampler : public KMeanImageSampler {
GFX_EXPORT SkColor FindClosestColor(const uint8_t* image, int width, int height,
SkColor color);
-// Returns an SkColor that represents the calculated dominant color in the png.
-// This uses a KMean clustering algorithm to find clusters of pixel colors in
-// RGB space.
-// |png| represents the data of a png encoded image.
-// |darkness_limit| represents the minimum sum of the RGB components that is
-// acceptable as a color choice. This can be from 0 to 765.
-// |brightness_limit| represents the maximum sum of the RGB components that is
-// acceptable as a color choice. This can be from 0 to 765.
+// Returns an SkColor that represents the calculated dominant color in the
+// image. This uses a KMean clustering algorithm to find clusters of pixel
+// colors in RGB space.
+// |png|/|bitmap| represents the data of a png/bitmap encoded image.
+// |lower_bound| represents the minimum bound of HSL values to allow.
+// |upper_bound| represents the maximum bound of HSL values to allow.
+// See color_utils::IsWithinHSLRange() for description of these bounds.
//
// RGB KMean Algorithm (N clusters, M iterations):
// 1.Pick N starting colors by randomly sampling the pixels. If you see a
@@ -82,21 +83,28 @@ GFX_EXPORT SkColor FindClosestColor(const uint8_t* image, int width, int height,
// the clusters by weight (where weight is the number of pixels that make up
// this cluster).
// 6.Going through the sorted list of clusters, pick the first cluster with the
-// largest weight that's centroid fulfills the equation
-// |darkness_limit| < SUM(R, G, B) < |brightness_limit|. Return that color.
+// largest weight that's centroid falls between |lower_bound| and
+// |upper_bound|. Return that color.
// If no color fulfills that requirement return the color with the largest
// weight regardless of whether or not it fulfills the equation above.
-//
-// Note: Switching to HSV space did not improve the results of this algorithm
-// for typical favicon images.
+GFX_EXPORT SkColor
+ CalculateKMeanColorOfPNG(scoped_refptr<base::RefCountedMemory> png,
+ const HSL& lower_bound,
+ const HSL& upper_bound,
+ KMeanImageSampler* sampler);
+// Computes a dominant color using the above algorithm and reasonable defaults
+// for |lower_bound|, |upper_bound| and |sampler|.
GFX_EXPORT SkColor CalculateKMeanColorOfPNG(
- scoped_refptr<base::RefCountedMemory> png,
- uint32_t darkness_limit,
- uint32_t brightness_limit,
- KMeanImageSampler* sampler);
-
-// Computes a dominant color for an SkBitmap using the above algorithm and
-// reasonable defaults for |darkness_limit|, |brightness_limit| and |sampler|.
+ scoped_refptr<base::RefCountedMemory> png);
+
+// Returns an SkColor that represents the calculated dominant color in the
+// image. See CalculateKMeanColorOfPNG() for details.
+GFX_EXPORT SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap,
+ const HSL& lower_bound,
+ const HSL& upper_bound,
+ KMeanImageSampler* sampler);
+// Computes a dominant color using the above algorithm and reasonable defaults
+// for |lower_bound|, |upper_bound| and |sampler|.
GFX_EXPORT SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap);
// Compute color covariance matrix for the input bitmap.
diff --git a/chromium/ui/gfx/color_analysis_unittest.cc b/chromium/ui/gfx/color_analysis_unittest.cc
index 7757eb959ba..8e6ec831c1e 100644
--- a/chromium/ui/gfx/color_analysis_unittest.cc
+++ b/chromium/ui/gfx/color_analysis_unittest.cc
@@ -10,11 +10,11 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/gfx/image/image.h"
#include "ui/gfx/rect.h"
-using color_utils::FindClosestColor;
-
-namespace {
+namespace color_utils {
const unsigned char k1x1White[] = {
0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a,
@@ -87,7 +87,24 @@ const unsigned char k1x3BlueRed[] = {
0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82
};
-class MockKMeanImageSampler : public color_utils::KMeanImageSampler {
+const HSL kDefaultLowerBound = {-1, -1, 0.15};
+const HSL kDefaultUpperBound = {-1, -1, 0.85};
+
+// Creates a 1-dimensional png of the pixel colors found in |colors|.
+scoped_refptr<base::RefCountedMemory> CreateTestPNG(
+ const std::vector<SkColor>& colors) {
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, colors.size(), 1);
+ bitmap.allocPixels();
+
+ SkAutoLockPixels lock(bitmap);
+ for (size_t i = 0; i < colors.size(); ++i) {
+ bitmap.eraseArea(SkIRect::MakeXYWH(i, 0, 1, 1), colors[i]);
+ }
+ return gfx::Image::CreateFrom1xBitmap(bitmap).As1xPNGBytes();
+}
+
+class MockKMeanImageSampler : public KMeanImageSampler {
public:
MockKMeanImageSampler() : current_result_index_(0) {
}
@@ -104,15 +121,6 @@ class MockKMeanImageSampler : public color_utils::KMeanImageSampler {
prebaked_sample_results_.push_back(sample);
}
- void Reset() {
- prebaked_sample_results_.clear();
- ResetCounter();
- }
-
- void ResetCounter() {
- current_result_index_ = 0;
- }
-
virtual int GetSample(int width, int height) OVERRIDE {
if (current_result_index_ >= prebaked_sample_results_.size()) {
current_result_index_ = 0;
@@ -156,8 +164,6 @@ void Calculate8bitBitmapMinMax(const SkBitmap& bitmap,
}
}
-} // namespace
-
class ColorAnalysisTest : public testing::Test {
};
@@ -171,13 +177,13 @@ TEST_F(ColorAnalysisTest, CalculatePNGKMeanAllWhite) {
k1x1White,
k1x1White + sizeof(k1x1White) / sizeof(unsigned char))));
- SkColor color =
- color_utils::CalculateKMeanColorOfPNG(png, 100, 600, &test_sampler);
+ SkColor color = CalculateKMeanColorOfPNG(
+ png, kDefaultLowerBound, kDefaultUpperBound, &test_sampler);
EXPECT_EQ(color, SK_ColorWHITE);
}
-TEST_F(ColorAnalysisTest, CalculatePNGKMeanIgnoreWhite) {
+TEST_F(ColorAnalysisTest, CalculatePNGKMeanIgnoreWhiteLightness) {
MockKMeanImageSampler test_sampler;
test_sampler.AddSample(0);
test_sampler.AddSample(1);
@@ -189,10 +195,10 @@ TEST_F(ColorAnalysisTest, CalculatePNGKMeanIgnoreWhite) {
k1x3BlueWhite,
k1x3BlueWhite + sizeof(k1x3BlueWhite) / sizeof(unsigned char))));
- SkColor color =
- color_utils::CalculateKMeanColorOfPNG(png, 100, 600, &test_sampler);
+ SkColor color = CalculateKMeanColorOfPNG(
+ png, kDefaultLowerBound, kDefaultUpperBound, &test_sampler);
- EXPECT_EQ(color, SkColorSetARGB(0xFF, 0x00, 0x00, 0xFF));
+ EXPECT_EQ(SkColorSetARGB(0xFF, 0x00, 0x00, 0xFF), color);
}
TEST_F(ColorAnalysisTest, CalculatePNGKMeanPickMostCommon) {
@@ -207,14 +213,51 @@ TEST_F(ColorAnalysisTest, CalculatePNGKMeanPickMostCommon) {
k1x3BlueRed,
k1x3BlueRed + sizeof(k1x3BlueRed) / sizeof(unsigned char))));
- SkColor color =
- color_utils::CalculateKMeanColorOfPNG(png, 100, 600, &test_sampler);
+ SkColor color = CalculateKMeanColorOfPNG(
+ png, kDefaultLowerBound, kDefaultUpperBound, &test_sampler);
- EXPECT_EQ(color, SkColorSetARGB(0xFF, 0xFF, 0x00, 0x00));
+ EXPECT_EQ(SkColorSetARGB(0xFF, 0xFF, 0x00, 0x00), color);
+}
+
+TEST_F(ColorAnalysisTest, CalculatePNGKMeanIgnoreRedHue) {
+ MockKMeanImageSampler test_sampler;
+ test_sampler.AddSample(0);
+ test_sampler.AddSample(1);
+ test_sampler.AddSample(2);
+
+ std::vector<SkColor> colors(4, SK_ColorRED);
+ colors[1] = SK_ColorBLUE;
+
+ scoped_refptr<base::RefCountedMemory> png = CreateTestPNG(colors);
+
+ HSL lower = {0.2, -1, 0.15};
+ HSL upper = {0.8, -1, 0.85};
+ SkColor color = CalculateKMeanColorOfPNG(
+ png, lower, upper, &test_sampler);
+
+ EXPECT_EQ(SK_ColorBLUE, color);
+}
+
+TEST_F(ColorAnalysisTest, CalculatePNGKMeanIgnoreGreySaturation) {
+ MockKMeanImageSampler test_sampler;
+ test_sampler.AddSample(0);
+ test_sampler.AddSample(1);
+ test_sampler.AddSample(2);
+
+ std::vector<SkColor> colors(4, SK_ColorGRAY);
+ colors[1] = SK_ColorBLUE;
+
+ scoped_refptr<base::RefCountedMemory> png = CreateTestPNG(colors);
+ HSL lower = {-1, 0.3, -1};
+ HSL upper = {-1, 1, -1};
+ SkColor color = CalculateKMeanColorOfPNG(
+ png, lower, upper, &test_sampler);
+
+ EXPECT_EQ(SK_ColorBLUE, color);
}
TEST_F(ColorAnalysisTest, GridSampler) {
- color_utils::GridSampler sampler;
+ GridSampler sampler;
const int kWidth = 16;
const int kHeight = 16;
// Sample starts at 1,1.
@@ -263,7 +306,7 @@ TEST_F(ColorAnalysisTest, CalculateKMeanColorOfBitmap) {
bitmap.allocPixels();
bitmap.eraseARGB(255, 100, 150, 200);
- SkColor color = color_utils::CalculateKMeanColorOfBitmap(bitmap);
+ SkColor color = CalculateKMeanColorOfBitmap(bitmap);
EXPECT_EQ(255u, SkColorGetA(color));
// Color values are not exactly equal due to reversal of premultiplied alpha.
EXPECT_TRUE(ChannelApproximatelyEqual(100, SkColorGetR(color)));
@@ -272,7 +315,7 @@ TEST_F(ColorAnalysisTest, CalculateKMeanColorOfBitmap) {
// Test a bitmap with an alpha channel.
bitmap.eraseARGB(128, 100, 150, 200);
- color = color_utils::CalculateKMeanColorOfBitmap(bitmap);
+ color = CalculateKMeanColorOfBitmap(bitmap);
// Alpha channel should be ignored for dominant color calculation.
EXPECT_EQ(255u, SkColorGetA(color));
@@ -285,11 +328,10 @@ TEST_F(ColorAnalysisTest, ComputeColorCovarianceTrivial) {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 100, 200);
- EXPECT_EQ(gfx::Matrix3F::Zeros(),
- color_utils::ComputeColorCovariance(bitmap));
+ EXPECT_EQ(gfx::Matrix3F::Zeros(), ComputeColorCovariance(bitmap));
bitmap.allocPixels();
- bitmap.eraseRGB(50, 150, 200);
- gfx::Matrix3F covariance = color_utils::ComputeColorCovariance(bitmap);
+ bitmap.eraseARGB(255, 50, 150, 200);
+ gfx::Matrix3F covariance = ComputeColorCovariance(bitmap);
// The answer should be all zeros.
EXPECT_TRUE(covariance == gfx::Matrix3F::Zeros());
}
@@ -306,7 +348,7 @@ TEST_F(ColorAnalysisTest, ComputeColorCovarianceWithCanvas) {
SkBitmap bitmap =
skia::GetTopDevice(*canvas.sk_canvas())->accessBitmap(false);
- gfx::Matrix3F covariance = color_utils::ComputeColorCovariance(bitmap);
+ gfx::Matrix3F covariance = ComputeColorCovariance(bitmap);
gfx::Matrix3F expected_covariance = gfx::Matrix3F::Zeros();
expected_covariance.set(2400, 400, -1600,
@@ -324,12 +366,11 @@ TEST_F(ColorAnalysisTest, ApplyColorReductionSingleColor) {
source.allocPixels();
result.allocPixels();
- source.eraseRGB(50, 150, 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(color_utils::ApplyColorReduction(
- source, transform, false, &result));
+ EXPECT_TRUE(ApplyColorReduction(source, transform, false, &result));
uint8_t min_gl = 0;
uint8_t max_gl = 0;
@@ -338,24 +379,21 @@ TEST_F(ColorAnalysisTest, ApplyColorReductionSingleColor) {
EXPECT_EQ(145, max_gl);
// Now scan requesting rescale. Expect all 0.
- EXPECT_TRUE(color_utils::ApplyColorReduction(
- source, transform, true, &result));
+ 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(color_utils::ApplyColorReduction(
- source, transform, false, &result));
+ 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(color_utils::ApplyColorReduction(
- source, transform, false, &result));
+ EXPECT_TRUE(ApplyColorReduction(source, transform, false, &result));
Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
EXPECT_EQ(0x0, min_gl);
EXPECT_EQ(0x0, max_gl);
@@ -376,8 +414,7 @@ TEST_F(ColorAnalysisTest, ApplyColorReductionBlackAndWhite) {
result.allocPixels();
gfx::Vector3dF transform(1.0f, 0.5f, 0.1f);
- EXPECT_TRUE(color_utils::ApplyColorReduction(
- source, transform, true, &result));
+ EXPECT_TRUE(ApplyColorReduction(source, transform, true, &result));
uint8_t min_gl = 0;
uint8_t max_gl = 0;
Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
@@ -389,8 +426,7 @@ TEST_F(ColorAnalysisTest, ApplyColorReductionBlackAndWhite) {
// Reverse test.
transform.Scale(-1.0f);
- EXPECT_TRUE(color_utils::ApplyColorReduction(
- source, transform, true, &result));
+ EXPECT_TRUE(ApplyColorReduction(source, transform, true, &result));
min_gl = 0;
max_gl = 0;
Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
@@ -417,8 +453,7 @@ TEST_F(ColorAnalysisTest, ApplyColorReductionMultiColor) {
result.allocPixels();
gfx::Vector3dF transform(1.0f, 0.5f, 0.1f);
- EXPECT_TRUE(color_utils::ApplyColorReduction(
- source, transform, false, &result));
+ EXPECT_TRUE(ApplyColorReduction(source, transform, false, &result));
uint8_t min_gl = 0;
uint8_t max_gl = 0;
Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
@@ -428,8 +463,7 @@ TEST_F(ColorAnalysisTest, ApplyColorReductionMultiColor) {
EXPECT_EQ(max_gl, SkColorGetA(result.getColor(150, 0)));
EXPECT_EQ(100U, SkColorGetA(result.getColor(0, 0)));
- EXPECT_TRUE(color_utils::ApplyColorReduction(
- source, transform, true, &result));
+ EXPECT_TRUE(ApplyColorReduction(source, transform, true, &result));
Calculate8bitBitmapMinMax(result, &min_gl, &max_gl);
EXPECT_EQ(0, min_gl);
EXPECT_EQ(255, max_gl);
@@ -445,10 +479,10 @@ TEST_F(ColorAnalysisTest, ComputePrincipalComponentImageNotComputable) {
source.allocPixels();
result.allocPixels();
- source.eraseRGB(50, 150, 200);
+ source.eraseARGB(255, 50, 150, 200);
// This computation should fail since all colors always vary together.
- EXPECT_FALSE(color_utils::ComputePrincipalComponentImage(source, &result));
+ EXPECT_FALSE(ComputePrincipalComponentImage(source, &result));
}
TEST_F(ColorAnalysisTest, ComputePrincipalComponentImage) {
@@ -465,7 +499,7 @@ TEST_F(ColorAnalysisTest, ComputePrincipalComponentImage) {
result.allocPixels();
// This computation should fail since all colors always vary together.
- EXPECT_TRUE(color_utils::ComputePrincipalComponentImage(source, &result));
+ EXPECT_TRUE(ComputePrincipalComponentImage(source, &result));
uint8_t min_gl = 0;
uint8_t max_gl = 0;
@@ -477,3 +511,5 @@ TEST_F(ColorAnalysisTest, ComputePrincipalComponentImage) {
EXPECT_EQ(max_gl, SkColorGetA(result.getColor(299, 199)));
EXPECT_EQ(93U, SkColorGetA(result.getColor(150, 0)));
}
+
+} // namespace color_utils
diff --git a/chromium/ui/gfx/color_profile.cc b/chromium/ui/gfx/color_profile.cc
index fcd9a52ea0c..bb7c3d546c2 100644
--- a/chromium/ui/gfx/color_profile.cc
+++ b/chromium/ui/gfx/color_profile.cc
@@ -8,8 +8,15 @@ namespace gfx {
#if defined(OS_WIN) || defined(OS_MACOSX)
void ReadColorProfile(std::vector<char>* profile);
+GFX_EXPORT bool GetDisplayColorProfile(const gfx::Rect& bounds,
+ std::vector<char>* profile);
#else
void ReadColorProfile(std::vector<char>* profile) { }
+GFX_EXPORT bool GetDisplayColorProfile(const gfx::Rect& bounds,
+ std::vector<char>* profile) {
+ // TODO(port): consider screen color profile support.
+ return false;
+}
#endif
ColorProfile::ColorProfile() {
diff --git a/chromium/ui/gfx/color_profile.h b/chromium/ui/gfx/color_profile.h
index 20a02bf169f..790bfe57fff 100644
--- a/chromium/ui/gfx/color_profile.h
+++ b/chromium/ui/gfx/color_profile.h
@@ -7,8 +7,7 @@
#include <vector>
-#include "base/basictypes.h"
-
+#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/gfx_export.h"
namespace gfx {
@@ -31,10 +30,16 @@ class GFX_EXPORT ColorProfile {
DISALLOW_COPY_AND_ASSIGN(ColorProfile);
};
-// Loads the monitor color space if available.
-GFX_EXPORT void GetColorProfile(std::vector<char>* profile);
+inline bool InvalidColorProfileLength(size_t length) {
+ return (length < kMinProfileLength) || (length > kMaxProfileLength);
+}
+// Return the color profile of the display nearest the screen bounds. On Win32,
+// this may read a file from disk, so it shouldn't be run on the UI/IO threads.
+// If the given bounds are empty, or are off-screen, return false meaning there
+// is no color profile associated with the bounds.
+GFX_EXPORT bool GetDisplayColorProfile(const gfx::Rect& bounds,
+ std::vector<char>* profile);
} // namespace gfx
#endif // UI_GFX_COLOR_PROFILE_H_
-
diff --git a/chromium/ui/gfx/color_profile_mac.cc b/chromium/ui/gfx/color_profile_mac.cc
deleted file mode 100644
index 2c7f686a5f4..00000000000
--- a/chromium/ui/gfx/color_profile_mac.cc
+++ /dev/null
@@ -1,27 +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 "ui/gfx/color_profile.h"
-
-#include "base/mac/mac_util.h"
-
-namespace gfx {
-
-void ReadColorProfile(std::vector<char>* profile) {
- CGColorSpaceRef monitor_color_space(base::mac::GetSystemColorSpace());
- base::ScopedCFTypeRef<CFDataRef> icc_profile(
- CGColorSpaceCopyICCProfile(monitor_color_space));
- if (icc_profile) {
- size_t length = CFDataGetLength(icc_profile);
- if (length > gfx::kMaxProfileLength)
- return;
- if (length < gfx::kMinProfileLength)
- return;
- const unsigned char* sys_profile = CFDataGetBytePtr(icc_profile);
- profile->assign(sys_profile, sys_profile + length);
- }
-}
-
-} // namespace gfx
-
diff --git a/chromium/ui/gfx/color_profile_mac.mm b/chromium/ui/gfx/color_profile_mac.mm
new file mode 100644
index 00000000000..c36072d9330
--- /dev/null
+++ b/chromium/ui/gfx/color_profile_mac.mm
@@ -0,0 +1,32 @@
+// 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/color_profile.h"
+
+#include "base/mac/mac_util.h"
+
+namespace gfx {
+
+bool GetDisplayColorProfile(const gfx::Rect& bounds,
+ std::vector<char>* profile) {
+ if (bounds.IsEmpty())
+ return false;
+ // TODO(noel): implement.
+ return false;
+}
+
+void ReadColorProfile(std::vector<char>* profile) {
+ CGColorSpaceRef monitor_color_space(base::mac::GetSystemColorSpace());
+ base::ScopedCFTypeRef<CFDataRef> icc_profile(
+ CGColorSpaceCopyICCProfile(monitor_color_space));
+ if (!icc_profile)
+ return;
+ size_t length = CFDataGetLength(icc_profile);
+ if (gfx::InvalidColorProfileLength(length))
+ return;
+ const unsigned char* data = CFDataGetBytePtr(icc_profile);
+ profile->assign(data, data + length);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/color_profile_win.cc b/chromium/ui/gfx/color_profile_win.cc
index 2e08a36d4b6..a22c3d96a18 100644
--- a/chromium/ui/gfx/color_profile_win.cc
+++ b/chromium/ui/gfx/color_profile_win.cc
@@ -4,32 +4,118 @@
#include "ui/gfx/color_profile.h"
+#include <map>
#include <windows.h>
#include "base/file_util.h"
+#include "base/lazy_instance.h"
+#include "base/synchronization/lock.h"
namespace gfx {
+class ColorProfileCache {
+ public:
+ // A thread-safe cache of color profiles keyed by windows device name.
+ ColorProfileCache() {}
+
+ bool Find(const std::wstring& device, std::vector<char>* profile) {
+ base::AutoLock lock(lock_);
+ DeviceColorProfile::const_iterator it = cache_.find(device);
+ if (it == cache_.end())
+ return false;
+ *profile = it->second;
+ return true;
+ }
+
+ void Insert(const std::wstring& device, const std::vector<char>& profile) {
+ base::AutoLock lock(lock_);
+ cache_[device] = profile;
+ }
+
+ bool Erase(const std::wstring& device) {
+ base::AutoLock lock(lock_);
+ DeviceColorProfile::iterator it = cache_.find(device);
+ if (it == cache_.end())
+ return false;
+ cache_.erase(device);
+ return true;
+ }
+
+ void Clear() {
+ base::AutoLock lock(lock_);
+ cache_.clear();
+ }
+
+ private:
+ typedef std::map<std::wstring, std::vector<char> > DeviceColorProfile;
+
+ DeviceColorProfile cache_;
+ base::Lock lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(ColorProfileCache);
+};
+
+base::LazyInstance<ColorProfileCache>::Leaky g_color_profile_cache =
+ LAZY_INSTANCE_INITIALIZER;
+
+inline ColorProfileCache& GetColorProfileCache() {
+ return g_color_profile_cache.Get();
+}
+
+bool GetDisplayColorProfile(const gfx::Rect& bounds,
+ std::vector<char>* profile) {
+ DCHECK(profile->empty());
+
+ RECT rect = bounds.ToRECT();
+ HMONITOR handle = ::MonitorFromRect(&rect, MONITOR_DEFAULTTONULL);
+ if (bounds.IsEmpty() || !handle)
+ return false;
+
+ MONITORINFOEX monitor;
+ monitor.cbSize = sizeof(MONITORINFOEX);
+ CHECK(::GetMonitorInfo(handle, &monitor));
+ if (GetColorProfileCache().Find(monitor.szDevice, profile))
+ return true;
+
+ HDC hdc = ::CreateDC(monitor.szDevice, NULL, NULL, NULL);
+ DWORD path_length = MAX_PATH;
+ WCHAR path[MAX_PATH + 1];
+ BOOL result = ::GetICMProfile(hdc, &path_length, path);
+ ::DeleteDC(hdc);
+ if (!result)
+ return false;
+
+ base::FilePath file_name = base::FilePath(path).BaseName();
+ if (file_name != base::FilePath(L"sRGB Color Space Profile.icm")) {
+ std::string data;
+ if (base::ReadFileToString(base::FilePath(path), &data))
+ profile->assign(data.data(), data.data() + data.size());
+ size_t length = profile->size();
+ if (gfx::InvalidColorProfileLength(length))
+ profile->clear();
+ }
+
+ GetColorProfileCache().Insert(monitor.szDevice, *profile);
+ return true;
+}
+
void ReadColorProfile(std::vector<char>* profile) {
// TODO: support multiple monitors.
HDC screen_dc = GetDC(NULL);
DWORD path_len = MAX_PATH;
WCHAR path[MAX_PATH + 1];
- BOOL res = GetICMProfile(screen_dc, &path_len, path);
+ BOOL result = GetICMProfile(screen_dc, &path_len, path);
ReleaseDC(NULL, screen_dc);
- if (!res)
+ if (!result)
return;
std::string profileData;
if (!base::ReadFileToString(base::FilePath(path), &profileData))
return;
size_t length = profileData.size();
- if (length > gfx::kMaxProfileLength)
- return;
- if (length < gfx::kMinProfileLength)
+ if (gfx::InvalidColorProfileLength(length))
return;
profile->assign(profileData.data(), profileData.data() + length);
}
} // namespace gfx
-
diff --git a/chromium/ui/gfx/color_profile_win_unittest.cc b/chromium/ui/gfx/color_profile_win_unittest.cc
new file mode 100644
index 00000000000..604ee36201b
--- /dev/null
+++ b/chromium/ui/gfx/color_profile_win_unittest.cc
@@ -0,0 +1,32 @@
+// 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/color_profile.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+bool TestColorProfileUsingScreenBounds(const gfx::Rect& bounds) {
+ std::vector<char> color_profile;
+ return gfx::GetDisplayColorProfile(bounds, &color_profile);
+}
+
+TEST(ColorProfileTest, GetDisplayColorProfile) {
+ const gfx::Rect in_screen_bounds(10, 10, 100, 100);
+ EXPECT_TRUE(TestColorProfileUsingScreenBounds(in_screen_bounds));
+}
+
+TEST(ColorProfileTest, GetDisplayColorProfileForOffScreenBounds) {
+ const gfx::Rect off_screen_bounds(-100, -100, 10, 10);
+ EXPECT_FALSE(TestColorProfileUsingScreenBounds(off_screen_bounds));
+}
+
+TEST(ColorProfileTest, GetDisplayColorProfileForEmptyBounds) {
+ const gfx::Rect empty_screen_bounds(10, 10, 0, 0);
+ EXPECT_TRUE(empty_screen_bounds.IsEmpty());
+ EXPECT_FALSE(TestColorProfileUsingScreenBounds(empty_screen_bounds));
+}
+
+} // namespace
diff --git a/chromium/ui/gfx/color_utils.cc b/chromium/ui/gfx/color_utils.cc
index 9ced80f3952..3e00326f522 100644
--- a/chromium/ui/gfx/color_utils.cc
+++ b/chromium/ui/gfx/color_utils.cc
@@ -151,6 +151,36 @@ SkColor HSLToSkColor(const HSL& hsl, SkAlpha alpha) {
calcHue(temp1, temp2, hue - 1.0 / 3.0));
}
+bool IsWithinHSLRange(const HSL& hsl,
+ const HSL& lower_bound,
+ const HSL& upper_bound) {
+ DCHECK(hsl.h >= 0 && hsl.h <= 1) << hsl.h;
+ DCHECK(hsl.s >= 0 && hsl.s <= 1) << hsl.s;
+ DCHECK(hsl.l >= 0 && hsl.l <= 1) << hsl.l;
+ DCHECK(lower_bound.h < 0 || upper_bound.h < 0 ||
+ (lower_bound.h <= 1 && upper_bound.h <= lower_bound.h + 1))
+ << "lower_bound.h: " << lower_bound.h
+ << ", upper_bound.h: " << upper_bound.h;
+ DCHECK(lower_bound.s < 0 || upper_bound.s < 0 ||
+ (lower_bound.s <= upper_bound.s && upper_bound.s <= 1))
+ << "lower_bound.s: " << lower_bound.s
+ << ", upper_bound.s: " << upper_bound.s;
+ DCHECK(lower_bound.l < 0 || upper_bound.l < 0 ||
+ (lower_bound.l <= upper_bound.l && upper_bound.l <= 1))
+ << "lower_bound.l: " << lower_bound.l
+ << ", upper_bound.l: " << upper_bound.l;
+
+ // If the upper hue is >1, the given hue bounds wrap around at 1.
+ bool matches_hue = upper_bound.h > 1
+ ? hsl.h >= lower_bound.h || hsl.h <= upper_bound.h - 1
+ : hsl.h >= lower_bound.h && hsl.h <= upper_bound.h;
+ return (upper_bound.h < 0 || lower_bound.h < 0 || matches_hue) &&
+ (upper_bound.s < 0 || lower_bound.s < 0 ||
+ (hsl.s >= lower_bound.s && hsl.s <= upper_bound.s)) &&
+ (upper_bound.l < 0 || lower_bound.l < 0 ||
+ (hsl.l >= lower_bound.l && hsl.l <= upper_bound.l));
+}
+
SkColor HSLShift(SkColor color, const HSL& shift) {
HSL hsl;
int alpha = SkColorGetA(color);
@@ -194,7 +224,7 @@ SkColor HSLShift(SkColor color, const HSL& shift) {
}
void BuildLumaHistogram(const SkBitmap& bitmap, int histogram[256]) {
- DCHECK_EQ(SkBitmap::kARGB_8888_Config, bitmap.config());
+ DCHECK_EQ(kPMColor_SkColorType, bitmap.colorType());
SkAutoLockPixels bitmap_lock(bitmap);
diff --git a/chromium/ui/gfx/color_utils.h b/chromium/ui/gfx/color_utils.h
index 6dd6300aa3b..9446654cdbe 100644
--- a/chromium/ui/gfx/color_utils.h
+++ b/chromium/ui/gfx/color_utils.h
@@ -29,6 +29,20 @@ GFX_EXPORT double RelativeLuminance(SkColor color);
GFX_EXPORT void SkColorToHSL(SkColor c, HSL* hsl);
GFX_EXPORT SkColor HSLToSkColor(const HSL& hsl, SkAlpha alpha);
+// Determines whether the given |hsl| falls within the given range for each
+// component. All components of |hsl| are expected to be in the range [0, 1].
+//
+// If a component is negative in either |lower_bound| or |upper_bound|, that
+// component will be ignored.
+//
+// For hue, the lower bound should be in the range [0, 1] and the upper bound
+// should be in the range [(lower bound), (lower bound + 1)].
+// For saturation and value, bounds should be specified in the range [0, 1],
+// with the lower bound less than the upper bound.
+GFX_EXPORT bool IsWithinHSLRange(const HSL& hsl,
+ const HSL& lower_bound,
+ const HSL& upper_bound);
+
// HSL-Shift an SkColor. The shift values are in the range of 0-1, with the
// option to specify -1 for 'no change'. The shift values are defined as:
// hsl_shift[0] (hue): The absolute hue value - 0 and 1 map
diff --git a/chromium/ui/gfx/color_utils_unittest.cc b/chromium/ui/gfx/color_utils_unittest.cc
index 59eaeba1e3e..b90ae8e2c42 100644
--- a/chromium/ui/gfx/color_utils_unittest.cc
+++ b/chromium/ui/gfx/color_utils_unittest.cc
@@ -9,17 +9,19 @@
#include "third_party/skia/include/core/SkColorPriv.h"
#include "ui/gfx/color_utils.h"
+namespace color_utils {
+
TEST(ColorUtils, SkColorToHSLRed) {
- color_utils::HSL hsl = { 0, 0, 0 };
- color_utils::SkColorToHSL(SK_ColorRED, &hsl);
+ HSL hsl = {0, 0, 0};
+ SkColorToHSL(SK_ColorRED, &hsl);
EXPECT_DOUBLE_EQ(hsl.h, 0);
EXPECT_DOUBLE_EQ(hsl.s, 1);
EXPECT_DOUBLE_EQ(hsl.l, 0.5);
}
TEST(ColorUtils, SkColorToHSLGrey) {
- color_utils::HSL hsl = { 0, 0, 0 };
- color_utils::SkColorToHSL(SkColorSetARGB(255, 128, 128, 128), &hsl);
+ HSL hsl = {0, 0, 0};
+ SkColorToHSL(SkColorSetARGB(255, 128, 128, 128), &hsl);
EXPECT_DOUBLE_EQ(hsl.h, 0);
EXPECT_DOUBLE_EQ(hsl.s, 0);
EXPECT_EQ(static_cast<int>(hsl.l * 100),
@@ -28,24 +30,23 @@ TEST(ColorUtils, SkColorToHSLGrey) {
TEST(ColorUtils, HSLToSkColorWithAlpha) {
SkColor red = SkColorSetARGB(128, 255, 0, 0);
- color_utils::HSL hsl = { 0, 1, 0.5 };
- SkColor result = color_utils::HSLToSkColor(hsl, 128);
+ HSL hsl = {0, 1, 0.5};
+ SkColor result = HSLToSkColor(hsl, 128);
EXPECT_EQ(SkColorGetA(red), SkColorGetA(result));
EXPECT_EQ(SkColorGetR(red), SkColorGetR(result));
EXPECT_EQ(SkColorGetG(red), SkColorGetG(result));
EXPECT_EQ(SkColorGetB(red), SkColorGetB(result));
}
-
TEST(ColorUtils, RGBtoHSLRoundTrip) {
// Just spot check values near the edges.
for (int r = 0; r < 10; ++r) {
for (int g = 0; g < 10; ++g) {
for (int b = 0; b < 10; ++b) {
SkColor rgb = SkColorSetARGB(255, r, g, b);
- color_utils::HSL hsl = { 0, 0, 0 };
- color_utils::SkColorToHSL(rgb, &hsl);
- SkColor out = color_utils::HSLToSkColor(hsl, 255);
+ HSL hsl = {0, 0, 0};
+ SkColorToHSL(rgb, &hsl);
+ SkColor out = HSLToSkColor(hsl, 255);
EXPECT_EQ(SkColorGetR(out), SkColorGetR(rgb));
EXPECT_EQ(SkColorGetG(out), SkColorGetG(rgb));
EXPECT_EQ(SkColorGetB(out), SkColorGetB(rgb));
@@ -56,9 +57,9 @@ TEST(ColorUtils, RGBtoHSLRoundTrip) {
for (int g = 240; g < 256; ++g) {
for (int b = 240; b < 256; ++b) {
SkColor rgb = SkColorSetARGB(255, r, g, b);
- color_utils::HSL hsl = { 0, 0, 0 };
- color_utils::SkColorToHSL(rgb, &hsl);
- SkColor out = color_utils::HSLToSkColor(hsl, 255);
+ HSL hsl = {0, 0, 0};
+ SkColorToHSL(rgb, &hsl);
+ SkColor out = HSLToSkColor(hsl, 255);
EXPECT_EQ(SkColorGetR(out), SkColorGetR(rgb));
EXPECT_EQ(SkColorGetG(out), SkColorGetG(rgb));
EXPECT_EQ(SkColorGetB(out), SkColorGetB(rgb));
@@ -67,12 +68,44 @@ TEST(ColorUtils, RGBtoHSLRoundTrip) {
}
}
+TEST(ColorUtils, IsWithinHSLRange) {
+ HSL hsl = {0.3, 0.4, 0.5};
+ HSL lower = {0.2, 0.3, 0.4};
+ HSL upper = {0.4, 0.5, 0.6};
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ // Bounds are inclusive.
+ hsl.h = 0.2;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ hsl.h = 0.4;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ hsl.s = 0.3;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ hsl.s = 0.5;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ hsl.l = 0.4;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ hsl.l = 0.6;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+}
+
+TEST(ColorUtils, IsWithinHSLRangeHueWrapAround) {
+ HSL hsl = {0.3, 0.4, 0.5};
+ HSL lower = {0.8, -1, -1};
+ HSL upper = {1.2, -1, -1};
+ hsl.h = 0.1;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ hsl.h = 0.9;
+ EXPECT_TRUE(IsWithinHSLRange(hsl, lower, upper));
+ hsl.h = 0.3;
+ EXPECT_FALSE(IsWithinHSLRange(hsl, lower, upper));
+}
+
TEST(ColorUtils, ColorToHSLRegisterSpill) {
// In a opt build on Linux, this was causing a register spill on my laptop
// (Pentium M) when converting from SkColor to HSL.
SkColor input = SkColorSetARGB(255, 206, 154, 89);
- color_utils::HSL hsl = { -1, -1, -1 };
- SkColor result = color_utils::HSLShift(input, hsl);
+ HSL hsl = {-1, -1, -1};
+ SkColor result = HSLShift(input, hsl);
// |result| should be the same as |input| since we passed in a value meaning
// no color shift.
EXPECT_EQ(SkColorGetA(input), SkColorGetA(result));
@@ -85,16 +118,16 @@ TEST(ColorUtils, AlphaBlend) {
SkColor fore = SkColorSetARGB(255, 200, 200, 200);
SkColor back = SkColorSetARGB(255, 100, 100, 100);
- EXPECT_TRUE(color_utils::AlphaBlend(fore, back, 255) ==
- fore);
- EXPECT_TRUE(color_utils::AlphaBlend(fore, back, 0) ==
- back);
+ EXPECT_TRUE(AlphaBlend(fore, back, 255) == fore);
+ EXPECT_TRUE(AlphaBlend(fore, back, 0) == back);
// One is fully transparent, result is partially transparent.
back = SkColorSetA(back, 0);
- EXPECT_EQ(136U, SkColorGetA(color_utils::AlphaBlend(fore, back, 136)));
+ EXPECT_EQ(136U, SkColorGetA(AlphaBlend(fore, back, 136)));
// Both are fully transparent, result is fully transparent.
fore = SkColorSetA(fore, 0);
- EXPECT_EQ(0U, SkColorGetA(color_utils::AlphaBlend(fore, back, 255)));
+ EXPECT_EQ(0U, SkColorGetA(AlphaBlend(fore, back, 255)));
}
+
+} // namespace color_utils
diff --git a/chromium/ui/gfx/display.cc b/chromium/ui/gfx/display.cc
index 024b1f9aaa6..029359c0938 100644
--- a/chromium/ui/gfx/display.cc
+++ b/chromium/ui/gfx/display.cc
@@ -35,12 +35,11 @@ float GetForcedDeviceScaleFactorImpl() {
return static_cast<float>(scale_in_double);
}
-const int64 kInvalidDisplayIDForCompileTimeInit = -1;
-int64 internal_display_id_ = kInvalidDisplayIDForCompileTimeInit;
+int64 internal_display_id_ = -1;
} // namespace
-const int64 Display::kInvalidDisplayID = kInvalidDisplayIDForCompileTimeInit;
+const int64 Display::kInvalidDisplayID = -1;
// static
float Display::GetForcedDeviceScaleFactor() {
@@ -51,7 +50,9 @@ float Display::GetForcedDeviceScaleFactor() {
//static
bool Display::HasForceDeviceScaleFactor() {
- return HasForceDeviceScaleFactorImpl();
+ static const bool kHasForceDeviceScaleFactor =
+ HasForceDeviceScaleFactorImpl();
+ return kHasForceDeviceScaleFactor;
}
Display::Display()
@@ -83,6 +84,42 @@ Display::Display(int64 id, const gfx::Rect& bounds)
Display::~Display() {
}
+int Display::RotationAsDegree() const {
+ switch (rotation_) {
+ case ROTATE_0:
+ return 0;
+ case ROTATE_90:
+ return 90;
+ case ROTATE_180:
+ return 180;
+ case ROTATE_270:
+ return 270;
+ }
+
+ NOTREACHED();
+ return 0;
+}
+
+void Display::SetRotationAsDegree(int rotation) {
+ switch (rotation) {
+ case 0:
+ rotation_ = ROTATE_0;
+ break;
+ case 90:
+ rotation_ = ROTATE_90;
+ break;
+ case 180:
+ rotation_ = ROTATE_180;
+ break;
+ case 270:
+ rotation_ = ROTATE_270;
+ break;
+ default:
+ // We should not reach that but we will just ignore the call if we do.
+ NOTREACHED();
+ }
+}
+
Insets Display::GetWorkAreaInsets() const {
return gfx::Insets(work_area_.y() - bounds_.y(),
work_area_.x() - bounds_.x(),
diff --git a/chromium/ui/gfx/display.h b/chromium/ui/gfx/display.h
index eb35a5f5c6f..90fc42f5c31 100644
--- a/chromium/ui/gfx/display.h
+++ b/chromium/ui/gfx/display.h
@@ -73,6 +73,8 @@ class GFX_EXPORT Display {
Rotation rotation() const { return rotation_; }
void set_rotation(Rotation rotation) { rotation_ = rotation; }
+ int RotationAsDegree() const;
+ void SetRotationAsDegree(int rotation);
TouchSupport touch_support() const { return touch_support_; }
void set_touch_support(TouchSupport support) { touch_support_ = support; }
diff --git a/chromium/ui/gfx/display_observer.h b/chromium/ui/gfx/display_observer.h
index ca97247f9ed..0730f266206 100644
--- a/chromium/ui/gfx/display_observer.h
+++ b/chromium/ui/gfx/display_observer.h
@@ -5,6 +5,8 @@
#ifndef UI_GFX_DISPLAY_OBSERVER_H_
#define UI_GFX_DISPLAY_OBSERVER_H_
+#include <stdint.h>
+
#include "ui/gfx/gfx_export.h"
namespace gfx {
@@ -15,8 +17,13 @@ class Display;
// |DisplaySettingsProvier|. crbug.com/122863.
class GFX_EXPORT DisplayObserver {
public:
- // Called when the |display|'s bound has changed.
- virtual void OnDisplayBoundsChanged(const Display& display) = 0;
+ enum DisplayMetric {
+ DISPLAY_METRIC_NONE = 0,
+ DISPLAY_METRIC_BOUNDS = 1 << 0,
+ DISPLAY_METRIC_WORK_AREA = 1 << 1,
+ DISPLAY_METRIC_DEVICE_SCALE_FACTOR = 1 << 2,
+ DISPLAY_METRIC_ROTATION = 1 << 3,
+ };
// Called when |new_display| has been added.
virtual void OnDisplayAdded(const Display& new_display) = 0;
@@ -24,6 +31,11 @@ class GFX_EXPORT DisplayObserver {
// Called when |old_display| has been removed.
virtual void OnDisplayRemoved(const Display& old_display) = 0;
+ // Called when a |display| has one or more metrics changed. |changed_metrics|
+ // will contain the information about the change, see |DisplayMetric|.
+ virtual void OnDisplayMetricsChanged(const Display& display,
+ uint32_t changed_metrics) = 0;
+
protected:
virtual ~DisplayObserver();
};
diff --git a/chromium/ui/gfx/font.cc b/chromium/ui/gfx/font.cc
index 9eea73b608a..31f27b4f294 100644
--- a/chromium/ui/gfx/font.cc
+++ b/chromium/ui/gfx/font.cc
@@ -18,7 +18,7 @@ Font::Font() : platform_font_(PlatformFont::CreateDefault()) {
Font::Font(const Font& other) : platform_font_(other.platform_font_) {
}
-gfx::Font& Font::operator=(const Font& other) {
+Font& Font::operator=(const Font& other) {
platform_font_ = other.platform_font_;
return *this;
}
@@ -38,11 +38,7 @@ Font::Font(const std::string& font_name, int font_size)
Font::~Font() {
}
-Font Font::DeriveFont(int size_delta) const {
- return DeriveFont(size_delta, GetStyle());
-}
-
-Font Font::DeriveFont(int size_delta, int style) const {
+Font Font::Derive(int size_delta, int style) const {
return platform_font_->DeriveFont(size_delta, style);
}
@@ -58,14 +54,6 @@ int Font::GetCapHeight() const {
return platform_font_->GetCapHeight();
}
-int Font::GetAverageCharacterWidth() const {
- return platform_font_->GetAverageCharacterWidth();
-}
-
-int Font::GetStringWidth(const base::string16& text) const {
- return platform_font_->GetStringWidth(text);
-}
-
int Font::GetExpectedTextWidth(int length) const {
return platform_font_->GetExpectedTextWidth(length);
}
diff --git a/chromium/ui/gfx/font.h b/chromium/ui/gfx/font.h
index 963dde70ffe..5ab0f170bda 100644
--- a/chromium/ui/gfx/font.h
+++ b/chromium/ui/gfx/font.h
@@ -42,7 +42,7 @@ class GFX_EXPORT Font {
// Creates a font that is a clone of another font object.
Font(const Font& other);
- gfx::Font& operator=(const Font& other);
+ Font& operator=(const Font& other);
// Creates a font from the specified native font.
explicit Font(NativeFont native_font);
@@ -57,16 +57,11 @@ class GFX_EXPORT Font {
~Font();
// Returns a new Font derived from the existing font.
- // |size_deta| is the size in pixels to add to the current font. For example,
+ // |size_delta| is the size in pixels to add to the current font. For example,
// a value of 5 results in a font 5 pixels bigger than this font.
- Font DeriveFont(int size_delta) const;
-
- // Returns a new Font derived from the existing font.
- // |size_delta| is the size in pixels to add to the current font. See the
- // single argument version of this method for an example.
// The style parameter specifies the new style for the font, and is a
// bitmask of the values: BOLD, ITALIC and UNDERLINE.
- Font DeriveFont(int size_delta, int style) const;
+ Font Derive(int size_delta, int style) const;
// Returns the number of vertical pixels needed to display characters from
// the specified font. This may include some leading, i.e. height may be
@@ -81,15 +76,8 @@ class GFX_EXPORT Font {
// Returns the cap height of the font.
int GetCapHeight() const;
- // Returns the average character width for the font.
- int GetAverageCharacterWidth() const;
-
- // Returns the number of horizontal pixels needed to display the specified
- // string.
- int GetStringWidth(const base::string16& text) const;
-
// Returns the expected number of horizontal pixels needed to display the
- // specified length of characters. Call GetStringWidth() to retrieve the
+ // specified length of characters. Call gfx::GetStringWidth() to retrieve the
// actual number.
int GetExpectedTextWidth(int length) const;
diff --git a/chromium/ui/gfx/font_fallback_win.cc b/chromium/ui/gfx/font_fallback_win.cc
index 40666ee239a..4426718959b 100644
--- a/chromium/ui/gfx/font_fallback_win.cc
+++ b/chromium/ui/gfx/font_fallback_win.cc
@@ -24,8 +24,9 @@ void QueryFontsFromRegistry(std::map<std::string, std::string>* map) {
base::win::RegistryValueIterator it(HKEY_LOCAL_MACHINE, kFonts);
for (; it.Valid(); ++it) {
- const std::string filename = StringToLowerASCII(WideToUTF8(it.Value()));
- (*map)[filename] = WideToUTF8(it.Name());
+ const std::string filename =
+ StringToLowerASCII(base::WideToUTF8(it.Value()));
+ (*map)[filename] = base::WideToUTF8(it.Name());
}
}
@@ -69,7 +70,7 @@ void QueryLinkedFontsFromRegistry(const Font& font,
if (FAILED(key.Open(HKEY_LOCAL_MACHINE, kSystemLink, KEY_READ)))
return;
- const std::wstring original_font_name = UTF8ToWide(font.GetFontName());
+ const std::wstring original_font_name = base::UTF8ToWide(font.GetFontName());
std::vector<std::wstring> values;
if (FAILED(key.ReadValues(original_font_name.c_str(), &values))) {
key.Close();
@@ -79,7 +80,8 @@ void QueryLinkedFontsFromRegistry(const Font& font,
std::string filename;
std::string font_name;
for (size_t i = 0; i < values.size(); ++i) {
- internal::ParseFontLinkEntry(WideToUTF8(values[i]), &filename, &font_name);
+ internal::ParseFontLinkEntry(
+ base::WideToUTF8(values[i]), &filename, &font_name);
// If the font name is present, add that directly, otherwise add the
// font names corresponding to the filename.
if (!font_name.empty()) {
@@ -178,7 +180,8 @@ void ParseFontFamilyString(const std::string& family,
const size_t index = font_names->back().find('(');
if (index != std::string::npos) {
font_names->back().resize(index);
- TrimWhitespace(font_names->back(), TRIM_TRAILING, &font_names->back());
+ base::TrimWhitespace(font_names->back(), base::TRIM_TRAILING,
+ &font_names->back());
}
}
}
diff --git a/chromium/ui/gfx/font_list.cc b/chromium/ui/gfx/font_list.cc
index 3b1ab9bcd1f..920204bf7a7 100644
--- a/chromium/ui/gfx/font_list.cc
+++ b/chromium/ui/gfx/font_list.cc
@@ -4,13 +4,9 @@
#include "ui/gfx/font_list.h"
-#include <algorithm>
-
#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
+#include "ui/gfx/font_list_impl.h"
namespace {
@@ -18,128 +14,37 @@ namespace {
base::LazyInstance<std::string>::Leaky g_default_font_description =
LAZY_INSTANCE_INITIALIZER;
-// Parses font description into |font_names|, |font_style| and |font_size|.
-void ParseFontDescriptionString(const std::string& font_description_string,
- std::vector<std::string>* font_names,
- int* font_style,
- int* font_size) {
- base::SplitString(font_description_string, ',', font_names);
- DCHECK_GT(font_names->size(), 1U);
-
- // The last item is [STYLE_OPTIONS] SIZE.
- std::vector<std::string> styles_size;
- base::SplitString(font_names->back(), ' ', &styles_size);
- DCHECK(!styles_size.empty());
- base::StringToInt(styles_size.back(), font_size);
- DCHECK_GT(*font_size, 0);
- font_names->pop_back();
-
- // Font supports BOLD and ITALIC; underline is supported via RenderText.
- *font_style = 0;
- for (size_t i = 0; i < styles_size.size() - 1; ++i) {
- // Styles are separated by white spaces. base::SplitString splits styles
- // by space, and it inserts empty string for continuous spaces.
- if (styles_size[i].empty())
- continue;
- if (!styles_size[i].compare("Bold"))
- *font_style |= gfx::Font::BOLD;
- else if (!styles_size[i].compare("Italic"))
- *font_style |= gfx::Font::ITALIC;
- else
- NOTREACHED();
- }
-}
-
-// Returns the font style and size as a string.
-std::string FontStyleAndSizeToString(int font_style, int font_size) {
- std::string result;
- if (font_style & gfx::Font::BOLD)
- result += "Bold ";
- if (font_style & gfx::Font::ITALIC)
- result += "Italic ";
- result += base::IntToString(font_size);
- result += "px";
- return result;
-}
-
-// Returns font description from |font_names|, |font_style|, and |font_size|.
-std::string BuildFontDescription(const std::vector<std::string>& font_names,
- int font_style,
- int font_size) {
- std::string description = JoinString(font_names, ',');
- description += "," + FontStyleAndSizeToString(font_style, font_size);
- return description;
-}
+// The default instance of gfx::FontListImpl.
+base::LazyInstance<scoped_refptr<gfx::FontListImpl> >::Leaky g_default_impl =
+ LAZY_INSTANCE_INITIALIZER;
+bool g_default_impl_initialized = false;
} // namespace
namespace gfx {
-FontList::FontList()
- : common_height_(-1),
- common_baseline_(-1),
- font_style_(-1),
- font_size_(-1) {
- // SetDefaultFontDescription() must be called and the default font description
- // must be set earlier than any call of the default constructor.
- DCHECK(!(g_default_font_description == NULL)) // != is not overloaded.
- << "SetDefaultFontDescription has not been called.";
+FontList::FontList() : impl_(GetDefaultImpl()) {}
- font_description_string_ = g_default_font_description.Get();
- if (font_description_string_.empty())
- fonts_.push_back(Font());
-}
+FontList::FontList(const FontList& other) : impl_(other.impl_) {}
FontList::FontList(const std::string& font_description_string)
- : font_description_string_(font_description_string),
- common_height_(-1),
- common_baseline_(-1),
- font_style_(-1),
- font_size_(-1) {
- DCHECK(!font_description_string.empty());
- // DCHECK description string ends with "px" for size in pixel.
- DCHECK(EndsWith(font_description_string, "px", true));
-}
+ : impl_(new FontListImpl(font_description_string)) {}
FontList::FontList(const std::vector<std::string>& font_names,
int font_style,
int font_size)
- : font_description_string_(BuildFontDescription(font_names, font_style,
- font_size)),
- common_height_(-1),
- common_baseline_(-1),
- font_style_(font_style),
- font_size_(font_size) {
- DCHECK(!font_names.empty());
- DCHECK(!font_names[0].empty());
-}
+ : impl_(new FontListImpl(font_names, font_style, font_size)) {}
FontList::FontList(const std::vector<Font>& fonts)
- : fonts_(fonts),
- common_height_(-1),
- common_baseline_(-1),
- font_style_(-1),
- font_size_(-1) {
- DCHECK(!fonts.empty());
- font_style_ = fonts[0].GetStyle();
- font_size_ = fonts[0].GetFontSize();
- if (DCHECK_IS_ON()) {
- for (size_t i = 1; i < fonts.size(); ++i) {
- DCHECK_EQ(fonts[i].GetStyle(), font_style_);
- DCHECK_EQ(fonts[i].GetFontSize(), font_size_);
- }
- }
-}
+ : impl_(new FontListImpl(fonts)) {}
-FontList::FontList(const Font& font)
- : common_height_(-1),
- common_baseline_(-1),
- font_style_(-1),
- font_size_(-1) {
- fonts_.push_back(font);
-}
+FontList::FontList(const Font& font) : impl_(new FontListImpl(font)) {}
-FontList::~FontList() {
+FontList::~FontList() {}
+
+FontList& FontList::operator=(const FontList& other) {
+ impl_ = other.impl_;
+ return *this;
}
// static
@@ -150,151 +55,75 @@ void FontList::SetDefaultFontDescription(const std::string& font_description) {
EndsWith(font_description, "px", true));
g_default_font_description.Get() = font_description;
+ g_default_impl_initialized = false;
}
-FontList FontList::DeriveFontList(int font_style) const {
- return DeriveFontListWithSizeDeltaAndStyle(0, font_style);
-}
-
-FontList FontList::DeriveFontListWithSize(int size) const {
- DCHECK_GT(size, 0);
- return DeriveFontListWithSizeDeltaAndStyle(size - GetFontSize(),
- GetFontStyle());
+FontList FontList::Derive(int size_delta, int font_style) const {
+ return FontList(impl_->Derive(size_delta, font_style));
}
-FontList FontList::DeriveFontListWithSizeDelta(int size_delta) const {
- return DeriveFontListWithSizeDeltaAndStyle(size_delta, GetFontStyle());
+FontList FontList::DeriveWithSizeDelta(int size_delta) const {
+ return Derive(size_delta, GetFontStyle());
}
-FontList FontList::DeriveFontListWithSizeDeltaAndStyle(int size_delta,
- int style) const {
- // If there is a font vector, derive from that.
- if (!fonts_.empty()) {
- std::vector<Font> fonts = fonts_;
- for (size_t i = 0; i < fonts.size(); ++i)
- fonts[i] = fonts[i].DeriveFont(size_delta, style);
- return FontList(fonts);
- }
-
- // Otherwise, parse the font description string to derive from it.
- std::vector<std::string> font_names;
- int old_size;
- int old_style;
- ParseFontDescriptionString(font_description_string_, &font_names,
- &old_style, &old_size);
- int size = old_size + size_delta;
- DCHECK_GT(size, 0);
- return FontList(font_names, style, size);
+FontList FontList::DeriveWithStyle(int font_style) const {
+ return Derive(0, font_style);
}
int FontList::GetHeight() const {
- if (common_height_ == -1)
- CacheCommonFontHeightAndBaseline();
- return common_height_;
+ return impl_->GetHeight();
}
int FontList::GetBaseline() const {
- if (common_baseline_ == -1)
- CacheCommonFontHeightAndBaseline();
- return common_baseline_;
+ return impl_->GetBaseline();
}
int FontList::GetCapHeight() const {
- // Assume the primary font is used to render Latin characters.
- return GetPrimaryFont().GetCapHeight();
-}
-
-int FontList::GetStringWidth(const base::string16& text) const {
- // Rely on the primary font metrics for the time being.
- // TODO(yukishiino): Not only the first font, all the fonts in the list should
- // be taken into account to compute the pixels needed to display |text|.
- // Also this method, including one in Font class, should be deprecated and
- // client code should call Canvas::GetStringWidth(text, font_list) directly.
- // Our plan is as follows:
- // 1. Introduce the FontList version of Canvas::GetStringWidth().
- // 2. Make client code call Canvas::GetStringWidth().
- // 3. Retire {Font,FontList}::GetStringWidth().
- return GetPrimaryFont().GetStringWidth(text);
+ return impl_->GetCapHeight();
}
int FontList::GetExpectedTextWidth(int length) const {
- // Rely on the primary font metrics for the time being.
- return GetPrimaryFont().GetExpectedTextWidth(length);
+ return impl_->GetExpectedTextWidth(length);
}
int FontList::GetFontStyle() const {
- if (font_style_ == -1)
- CacheFontStyleAndSize();
- return font_style_;
+ return impl_->GetFontStyle();
}
const std::string& FontList::GetFontDescriptionString() const {
- if (font_description_string_.empty()) {
- DCHECK(!fonts_.empty());
- for (size_t i = 0; i < fonts_.size(); ++i) {
- std::string name = fonts_[i].GetFontName();
- font_description_string_ += name;
- font_description_string_ += ',';
- }
- // All fonts have the same style and size.
- font_description_string_ +=
- FontStyleAndSizeToString(fonts_[0].GetStyle(), fonts_[0].GetFontSize());
- }
- return font_description_string_;
+ return impl_->GetFontDescriptionString();
}
int FontList::GetFontSize() const {
- if (font_size_ == -1)
- CacheFontStyleAndSize();
- return font_size_;
+ return impl_->GetFontSize();
}
const std::vector<Font>& FontList::GetFonts() const {
- if (fonts_.empty()) {
- DCHECK(!font_description_string_.empty());
-
- std::vector<std::string> font_names;
- ParseFontDescriptionString(font_description_string_, &font_names,
- &font_style_, &font_size_);
- for (size_t i = 0; i < font_names.size(); ++i) {
- DCHECK(!font_names[i].empty());
-
- Font font(font_names[i], font_size_);
- if (font_style_ == Font::NORMAL)
- fonts_.push_back(font);
- else
- fonts_.push_back(font.DeriveFont(0, font_style_));
- }
- }
- return fonts_;
+ return impl_->GetFonts();
}
const Font& FontList::GetPrimaryFont() const {
- return GetFonts()[0];
+ return impl_->GetPrimaryFont();
}
-void FontList::CacheCommonFontHeightAndBaseline() const {
- int ascent = 0;
- int descent = 0;
- const std::vector<Font>& fonts = GetFonts();
- for (std::vector<Font>::const_iterator i = fonts.begin();
- i != fonts.end(); ++i) {
- ascent = std::max(ascent, i->GetBaseline());
- descent = std::max(descent, i->GetHeight() - i->GetBaseline());
- }
- common_height_ = ascent + descent;
- common_baseline_ = ascent;
-}
+FontList::FontList(FontListImpl* impl) : impl_(impl) {}
+
+// static
+const scoped_refptr<FontListImpl>& FontList::GetDefaultImpl() {
+ // SetDefaultFontDescription() must be called and the default font description
+ // must be set earlier than any call of this function.
+ DCHECK(!(g_default_font_description == NULL)) // != is not overloaded.
+ << "SetDefaultFontDescription has not been called.";
-void FontList::CacheFontStyleAndSize() const {
- if (!fonts_.empty()) {
- font_style_ = fonts_[0].GetStyle();
- font_size_ = fonts_[0].GetFontSize();
- } else {
- std::vector<std::string> font_names;
- ParseFontDescriptionString(font_description_string_, &font_names,
- &font_style_, &font_size_);
+ if (!g_default_impl_initialized) {
+ g_default_impl.Get() =
+ g_default_font_description.Get().empty() ?
+ new FontListImpl(Font()) :
+ new FontListImpl(g_default_font_description.Get());
+ g_default_impl_initialized = true;
}
+
+ return g_default_impl.Get();
}
} // namespace gfx
diff --git a/chromium/ui/gfx/font_list.h b/chromium/ui/gfx/font_list.h
index e37fd625a23..1ba8ad1aff9 100644
--- a/chromium/ui/gfx/font_list.h
+++ b/chromium/ui/gfx/font_list.h
@@ -8,35 +8,35 @@
#include <string>
#include <vector>
+#include "base/memory/ref_counted.h"
#include "ui/gfx/font.h"
#include "ui/gfx/gfx_export.h"
namespace gfx {
-// FontList represents a list of fonts either in the form of Font vector or in
-// the form of a string representing font names, styles, and size.
-//
-// The string representation is in the form "FAMILY_LIST [STYLE_OPTIONS] SIZE",
-// where FAMILY_LIST is a comma separated list of families terminated by a
-// comma, STYLE_OPTIONS is a whitespace separated list of words where each word
-// describes one of style, variant, weight, stretch, or gravity, and SIZE is
-// a decimal number followed by "px" for absolute size. STYLE_OPTIONS may be
-// absent.
+class FontListImpl;
+
+// FontList represents a list of fonts and provides metrics which are common
+// in the fonts. FontList is copyable and it's quite cheap to copy.
//
-// The string format complies with that of Pango detailed at
+// The format of font description string complies with that of Pango detailed at
// http://developer.gnome.org/pango/stable/pango-Fonts.html#pango-font-description-from-string
-//
-// FontList could be initialized either way without conversion to the other
-// form. The conversion to the other form is done only when asked to get the
-// other form.
-//
-// FontList allows operator= since FontList is a data member type in RenderText,
-// and operator= is used in RenderText::SetFontList().
+// The format is "<FONT_FAMILY_LIST>,[STYLES] <SIZE>" where
+// FONT_FAMILY_LIST is a comma-separated list of font family names,
+// STYLES is a space-separated list of style names ("Bold" and "Italic"),
+// SIZE is a font size in pixel with the suffix "px".
+// Here are examples of font description string:
+// "Arial, Helvetica, Bold Italic 14px"
+// "Arial, 14px"
class GFX_EXPORT FontList {
public:
- // Creates a font list with a Font with default name and style.
+ // Creates a font list with default font names, size and style, which are
+ // specified by SetDefaultFontDescription().
FontList();
+ // Creates a font list that is a clone of another font list.
+ FontList(const FontList& other);
+
// Creates a font list from a string representing font names, styles, and
// size.
explicit FontList(const std::string& font_description_string);
@@ -55,6 +55,9 @@ class GFX_EXPORT FontList {
~FontList();
+ // Copies the given font list into this object.
+ FontList& operator=(const FontList& other);
+
// Sets the description string for default FontList construction. If it's
// empty, FontList will initialize using the default Font constructor.
//
@@ -65,23 +68,20 @@ class GFX_EXPORT FontList {
// is changed.
static void SetDefaultFontDescription(const std::string& font_description);
- // Returns a new FontList with the given |font_style| flags.
- FontList DeriveFontList(int font_style) const;
-
- // Returns a new FontList with the same font names and style but with the
- // given font |size| in pixels.
- FontList DeriveFontListWithSize(int size) const;
-
- // Returns a new FontList with the same font names and style but resized.
- // |size_delta| is the size in pixels to add to the current font size.
- FontList DeriveFontListWithSizeDelta(int size_delta) const;
-
// Returns a new FontList with the same font names but resized and the given
// style. |size_delta| is the size in pixels to add to the current font size.
// |font_style| specifies the new style, which is a bitmask of the values:
// Font::BOLD, Font::ITALIC and Font::UNDERLINE.
- FontList DeriveFontListWithSizeDeltaAndStyle(int size_delta,
- int font_style) const;
+ FontList Derive(int size_delta, int font_style) const;
+
+ // Returns a new FontList with the same font names and style but resized.
+ // |size_delta| is the size in pixels to add to the current font size.
+ FontList DeriveWithSizeDelta(int size_delta) const;
+
+ // Returns a new FontList with the same font names and size but the given
+ // style. |font_style| specifies the new style, which is a bitmask of the
+ // values: Font::BOLD, Font::ITALIC and Font::UNDERLINE.
+ FontList DeriveWithStyle(int font_style) const;
// Returns the height of this font list, which is max(ascent) + max(descent)
// for all the fonts in the font list.
@@ -95,9 +95,6 @@ class GFX_EXPORT FontList {
// Currently returns the cap height of the primary font.
int GetCapHeight() const;
- // Returns the number of horizontal pixels needed to display |text|.
- int GetStringWidth(const base::string16& text) const;
-
// Returns the expected number of horizontal pixels needed to display the
// specified length of characters. Call GetStringWidth() to retrieve the
// actual number.
@@ -121,33 +118,11 @@ class GFX_EXPORT FontList {
const Font& GetPrimaryFont() const;
private:
- // Extracts common font height and baseline into |common_height_| and
- // |common_baseline_|.
- void CacheCommonFontHeightAndBaseline() const;
-
- // Extracts font style and size into |font_style_| and |font_size_|.
- void CacheFontStyleAndSize() const;
-
- // A vector of Font. If FontList is constructed with font description string,
- // |fonts_| is not initialized during construction. Instead, it is computed
- // lazily when user asked to get the font vector.
- mutable std::vector<Font> fonts_;
-
- // A string representing font names, styles, and sizes.
- // Please refer to the comments before class declaration for details on string
- // format.
- // If FontList is constructed with a vector of font,
- // |font_description_string_| is not initialized during construction. Instead,
- // it is computed lazily when user asked to get the font description string.
- mutable std::string font_description_string_;
-
- // The cached common height and baseline of the fonts in the font list.
- mutable int common_height_;
- mutable int common_baseline_;
-
- // Cached font style and size.
- mutable int font_style_;
- mutable int font_size_;
+ explicit FontList(FontListImpl* impl);
+
+ static const scoped_refptr<FontListImpl>& GetDefaultImpl();
+
+ scoped_refptr<FontListImpl> impl_;
};
} // namespace gfx
diff --git a/chromium/ui/gfx/font_list_impl.cc b/chromium/ui/gfx/font_list_impl.cc
new file mode 100644
index 00000000000..8c00fcc8278
--- /dev/null
+++ b/chromium/ui/gfx/font_list_impl.cc
@@ -0,0 +1,248 @@
+// 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/font_list_impl.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "ui/gfx/font.h"
+
+namespace {
+
+// Parses font description into |font_names|, |font_style| and |font_size|.
+void ParseFontDescriptionString(const std::string& font_description_string,
+ std::vector<std::string>* font_names,
+ int* font_style,
+ int* font_size) {
+ base::SplitString(font_description_string, ',', font_names);
+ DCHECK_GT(font_names->size(), 1U);
+
+ // The last item is [STYLE_OPTIONS] SIZE.
+ std::vector<std::string> styles_size;
+ base::SplitString(font_names->back(), ' ', &styles_size);
+ DCHECK(!styles_size.empty());
+ base::StringToInt(styles_size.back(), font_size);
+ DCHECK_GT(*font_size, 0);
+ font_names->pop_back();
+
+ // Font supports BOLD and ITALIC; underline is supported via RenderText.
+ *font_style = 0;
+ for (size_t i = 0; i < styles_size.size() - 1; ++i) {
+ // Styles are separated by white spaces. base::SplitString splits styles
+ // by space, and it inserts empty string for continuous spaces.
+ if (styles_size[i].empty())
+ continue;
+ if (!styles_size[i].compare("Bold"))
+ *font_style |= gfx::Font::BOLD;
+ else if (!styles_size[i].compare("Italic"))
+ *font_style |= gfx::Font::ITALIC;
+ else
+ NOTREACHED();
+ }
+}
+
+// Returns the font style and size as a string.
+std::string FontStyleAndSizeToString(int font_style, int font_size) {
+ std::string result;
+ if (font_style & gfx::Font::BOLD)
+ result += "Bold ";
+ if (font_style & gfx::Font::ITALIC)
+ result += "Italic ";
+ result += base::IntToString(font_size);
+ result += "px";
+ return result;
+}
+
+// Returns font description from |font_names|, |font_style|, and |font_size|.
+std::string BuildFontDescription(const std::vector<std::string>& font_names,
+ int font_style,
+ int font_size) {
+ std::string description = JoinString(font_names, ',');
+ description += "," + FontStyleAndSizeToString(font_style, font_size);
+ return description;
+}
+
+} // namespace
+
+namespace gfx {
+
+FontListImpl::FontListImpl(const std::string& font_description_string)
+ : font_description_string_(font_description_string),
+ common_height_(-1),
+ common_baseline_(-1),
+ font_style_(-1),
+ font_size_(-1) {
+ DCHECK(!font_description_string.empty());
+ // DCHECK description string ends with "px" for size in pixel.
+ DCHECK(EndsWith(font_description_string, "px", true));
+}
+
+FontListImpl::FontListImpl(const std::vector<std::string>& font_names,
+ int font_style,
+ int font_size)
+ : font_description_string_(BuildFontDescription(font_names, font_style,
+ font_size)),
+ common_height_(-1),
+ common_baseline_(-1),
+ font_style_(font_style),
+ font_size_(font_size) {
+ DCHECK(!font_names.empty());
+ DCHECK(!font_names[0].empty());
+}
+
+FontListImpl::FontListImpl(const std::vector<Font>& fonts)
+ : fonts_(fonts),
+ common_height_(-1),
+ common_baseline_(-1),
+ font_style_(-1),
+ font_size_(-1) {
+ DCHECK(!fonts.empty());
+ font_style_ = fonts[0].GetStyle();
+ font_size_ = fonts[0].GetFontSize();
+#if DCHECK_IS_ON
+ for (size_t i = 1; i < fonts.size(); ++i) {
+ DCHECK_EQ(fonts[i].GetStyle(), font_style_);
+ DCHECK_EQ(fonts[i].GetFontSize(), font_size_);
+ }
+#endif
+}
+
+FontListImpl::FontListImpl(const Font& font)
+ : common_height_(-1),
+ common_baseline_(-1),
+ font_style_(-1),
+ font_size_(-1) {
+ fonts_.push_back(font);
+}
+
+FontListImpl* FontListImpl::Derive(int size_delta, int font_style) const {
+ // If there is a font vector, derive from that.
+ if (!fonts_.empty()) {
+ std::vector<Font> fonts = fonts_;
+ for (size_t i = 0; i < fonts.size(); ++i)
+ fonts[i] = fonts[i].Derive(size_delta, font_style);
+ return new FontListImpl(fonts);
+ }
+
+ // Otherwise, parse the font description string to derive from it.
+ std::vector<std::string> font_names;
+ int old_size;
+ int old_style;
+ ParseFontDescriptionString(font_description_string_, &font_names,
+ &old_style, &old_size);
+ const int size = std::max(1, old_size + size_delta);
+ return new FontListImpl(font_names, font_style, size);
+}
+
+int FontListImpl::GetHeight() const {
+ if (common_height_ == -1)
+ CacheCommonFontHeightAndBaseline();
+ return common_height_;
+}
+
+int FontListImpl::GetBaseline() const {
+ if (common_baseline_ == -1)
+ CacheCommonFontHeightAndBaseline();
+ return common_baseline_;
+}
+
+int FontListImpl::GetCapHeight() const {
+ // Assume the primary font is used to render Latin characters.
+ return GetPrimaryFont().GetCapHeight();
+}
+
+int FontListImpl::GetExpectedTextWidth(int length) const {
+ // Rely on the primary font metrics for the time being.
+ return GetPrimaryFont().GetExpectedTextWidth(length);
+}
+
+int FontListImpl::GetFontStyle() const {
+ if (font_style_ == -1)
+ CacheFontStyleAndSize();
+ return font_style_;
+}
+
+const std::string& FontListImpl::GetFontDescriptionString() const {
+ if (font_description_string_.empty()) {
+ DCHECK(!fonts_.empty());
+ for (size_t i = 0; i < fonts_.size(); ++i) {
+ std::string name = fonts_[i].GetFontName();
+ font_description_string_ += name;
+ font_description_string_ += ',';
+ }
+ // All fonts have the same style and size.
+ font_description_string_ +=
+ FontStyleAndSizeToString(fonts_[0].GetStyle(), fonts_[0].GetFontSize());
+ }
+ return font_description_string_;
+}
+
+int FontListImpl::GetFontSize() const {
+ if (font_size_ == -1)
+ CacheFontStyleAndSize();
+ return font_size_;
+}
+
+const std::vector<Font>& FontListImpl::GetFonts() const {
+ if (fonts_.empty()) {
+ DCHECK(!font_description_string_.empty());
+
+ std::vector<std::string> font_names;
+ // It's possible that gfx::Font::UNDERLINE is specified and it's already
+ // stored in |font_style_| but |font_description_string_| doesn't have the
+ // underline info. So we should respect |font_style_| as long as it's
+ // valid.
+ int style = 0;
+ ParseFontDescriptionString(font_description_string_, &font_names,
+ &style, &font_size_);
+ if (font_style_ == -1)
+ font_style_ = style;
+ for (size_t i = 0; i < font_names.size(); ++i) {
+ DCHECK(!font_names[i].empty());
+
+ Font font(font_names[i], font_size_);
+ if (font_style_ == Font::NORMAL)
+ fonts_.push_back(font);
+ else
+ fonts_.push_back(font.Derive(0, font_style_));
+ }
+ }
+ return fonts_;
+}
+
+const Font& FontListImpl::GetPrimaryFont() const {
+ return GetFonts()[0];
+}
+
+FontListImpl::~FontListImpl() {}
+
+void FontListImpl::CacheCommonFontHeightAndBaseline() const {
+ int ascent = 0;
+ int descent = 0;
+ const std::vector<Font>& fonts = GetFonts();
+ for (std::vector<Font>::const_iterator i = fonts.begin();
+ i != fonts.end(); ++i) {
+ ascent = std::max(ascent, i->GetBaseline());
+ descent = std::max(descent, i->GetHeight() - i->GetBaseline());
+ }
+ common_height_ = ascent + descent;
+ common_baseline_ = ascent;
+}
+
+void FontListImpl::CacheFontStyleAndSize() const {
+ if (!fonts_.empty()) {
+ font_style_ = fonts_[0].GetStyle();
+ font_size_ = fonts_[0].GetFontSize();
+ } else {
+ std::vector<std::string> font_names;
+ ParseFontDescriptionString(font_description_string_, &font_names,
+ &font_style_, &font_size_);
+ }
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/font_list_impl.h b/chromium/ui/gfx/font_list_impl.h
new file mode 100644
index 00000000000..94bb33036ab
--- /dev/null
+++ b/chromium/ui/gfx/font_list_impl.h
@@ -0,0 +1,123 @@
+// 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_FONT_LIST_IMPL_H_
+#define UI_GFX_FONT_LIST_IMPL_H_
+
+#include <string>
+#include <vector>
+
+#include "base/memory/ref_counted.h"
+
+namespace gfx {
+
+class Font;
+
+// FontListImpl is designed to provide the implementation of FontList and
+// intended to be used only from FontList. You must not use this class
+// directly.
+//
+// FontListImpl represents a list of fonts either in the form of Font vector or
+// in the form of a string representing font names, styles, and size.
+//
+// FontListImpl could be initialized either way without conversion to the other
+// form. The conversion to the other form is done only when asked to get the
+// other form.
+//
+// For the format of font description string, see font_list.h for details.
+class FontListImpl : public base::RefCounted<FontListImpl> {
+ public:
+ // Creates a font list from a string representing font names, styles, and
+ // size.
+ explicit FontListImpl(const std::string& font_description_string);
+
+ // Creates a font list from font names, styles and size.
+ FontListImpl(const std::vector<std::string>& font_names,
+ int font_style,
+ int font_size);
+
+ // Creates a font list from a Font vector.
+ // All fonts in this vector should have the same style and size.
+ explicit FontListImpl(const std::vector<Font>& fonts);
+
+ // Creates a font list from a Font.
+ explicit FontListImpl(const Font& font);
+
+ // Returns a new FontListImpl with the same font names but resized and the
+ // given style. |size_delta| is the size in pixels to add to the current font
+ // size. |font_style| specifies the new style, which is a bitmask of the
+ // values: Font::BOLD, Font::ITALIC and Font::UNDERLINE.
+ FontListImpl* Derive(int size_delta, int font_style) const;
+
+ // Returns the height of this font list, which is max(ascent) + max(descent)
+ // for all the fonts in the font list.
+ int GetHeight() const;
+
+ // Returns the baseline of this font list, which is max(baseline) for all the
+ // fonts in the font list.
+ int GetBaseline() const;
+
+ // Returns the cap height of this font list.
+ // Currently returns the cap height of the primary font.
+ int GetCapHeight() const;
+
+ // Returns the expected number of horizontal pixels needed to display the
+ // specified length of characters. Call GetStringWidth() to retrieve the
+ // actual number.
+ int GetExpectedTextWidth(int length) const;
+
+ // Returns the |gfx::Font::FontStyle| style flags for this font list.
+ int GetFontStyle() const;
+
+ // Returns a string representing font names, styles, and size. If the
+ // FontListImpl is initialized by a vector of Font, use the first font's style
+ // and size for the description.
+ const std::string& GetFontDescriptionString() const;
+
+ // Returns the font size in pixels.
+ int GetFontSize() const;
+
+ // Returns the Font vector.
+ const std::vector<Font>& GetFonts() const;
+
+ // Returns the first font in the list.
+ const Font& GetPrimaryFont() const;
+
+ private:
+ friend class base::RefCounted<FontListImpl>;
+
+ ~FontListImpl();
+
+ // Extracts common font height and baseline into |common_height_| and
+ // |common_baseline_|.
+ void CacheCommonFontHeightAndBaseline() const;
+
+ // Extracts font style and size into |font_style_| and |font_size_|.
+ void CacheFontStyleAndSize() const;
+
+ // A vector of Font. If FontListImpl is constructed with font description
+ // string, |fonts_| is not initialized during construction. Instead, it is
+ // computed lazily when user asked to get the font vector.
+ mutable std::vector<Font> fonts_;
+
+ // A string representing font names, styles, and sizes.
+ // Please refer to the comments before class declaration for details on string
+ // format.
+ // If FontListImpl is constructed with a vector of font,
+ // |font_description_string_| is not initialized during construction. Instead,
+ // it is computed lazily when user asked to get the font description string.
+ mutable std::string font_description_string_;
+
+ // The cached common height and baseline of the fonts in the font list.
+ mutable int common_height_;
+ mutable int common_baseline_;
+
+ // Cached font style and size.
+ mutable int font_style_;
+ mutable int font_size_;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_FONT_LIST_IMPL_H_
diff --git a/chromium/ui/gfx/font_list_unittest.cc b/chromium/ui/gfx/font_list_unittest.cc
index 6cbb41fbecd..b96de46318b 100644
--- a/chromium/ui/gfx/font_list_unittest.cc
+++ b/chromium/ui/gfx/font_list_unittest.cc
@@ -24,6 +24,8 @@ std::string FontToString(const gfx::Font& font) {
font_string += "|bold";
if (style & gfx::Font::ITALIC)
font_string += "|italic";
+ if (style & gfx::Font::UNDERLINE)
+ font_string += "|underline";
return font_string;
}
@@ -43,9 +45,10 @@ TEST(FontListTest, FontDescString_FromFontNamesStyleAndSize) {
std::vector<std::string> font_names;
font_names.push_back("Arial");
font_names.push_back("Droid Sans serif");
- int font_style = Font::BOLD | Font::ITALIC;
+ int font_style = Font::BOLD | Font::ITALIC | Font::UNDERLINE;
int font_size = 11;
FontList font_list = FontList(font_names, font_style, font_size);
+ // "Underline" doesn't appear in the font description string.
EXPECT_EQ("Arial,Droid Sans serif,Bold Italic 11px",
font_list.GetFontDescriptionString());
}
@@ -60,11 +63,15 @@ TEST(FontListTest, FontDescString_FromFont) {
TEST(FontListTest, FontDescString_FromFontWithNonNormalStyle) {
// Test init from Font with non-normal style.
Font font("Arial", 8);
- FontList font_list = FontList(font.DeriveFont(2, Font::BOLD));
+ FontList font_list = FontList(font.Derive(2, Font::BOLD));
EXPECT_EQ("Arial,Bold 10px", font_list.GetFontDescriptionString());
- font_list = FontList(font.DeriveFont(-2, Font::ITALIC));
+ font_list = FontList(font.Derive(-2, Font::ITALIC));
EXPECT_EQ("Arial,Italic 6px", font_list.GetFontDescriptionString());
+
+ // "Underline" doesn't appear in the font description string.
+ font_list = FontList(font.Derive(-4, Font::UNDERLINE));
+ EXPECT_EQ("Arial,4px", font_list.GetFontDescriptionString());
}
TEST(FontListTest, FontDescString_FromFontVector) {
@@ -72,8 +79,8 @@ TEST(FontListTest, FontDescString_FromFontVector) {
Font font("Arial", 8);
Font font_1("Sans serif", 10);
std::vector<Font> fonts;
- fonts.push_back(font.DeriveFont(0, Font::BOLD));
- fonts.push_back(font_1.DeriveFont(-2, Font::BOLD));
+ fonts.push_back(font.Derive(0, Font::BOLD));
+ fonts.push_back(font_1.Derive(-2, Font::BOLD));
FontList font_list = FontList(fonts);
EXPECT_EQ("Arial,Sans serif,Bold 8px", font_list.GetFontDescriptionString());
}
@@ -118,12 +125,12 @@ TEST(FontListTest, Fonts_FromFont) {
TEST(FontListTest, Fonts_FromFontWithNonNormalStyle) {
// Test init from Font with non-normal style.
Font font("Arial", 8);
- FontList font_list = FontList(font.DeriveFont(2, Font::BOLD));
+ FontList font_list = FontList(font.Derive(2, Font::BOLD));
std::vector<Font> fonts = font_list.GetFonts();
EXPECT_EQ(1U, fonts.size());
EXPECT_EQ("Arial|10|bold", FontToString(fonts[0]));
- font_list = FontList(font.DeriveFont(-2, Font::ITALIC));
+ font_list = FontList(font.Derive(-2, Font::ITALIC));
fonts = font_list.GetFonts();
EXPECT_EQ(1U, fonts.size());
EXPECT_EQ("Arial|6|italic", FontToString(fonts[0]));
@@ -134,8 +141,8 @@ TEST(FontListTest, Fonts_FromFontVector) {
Font font("Arial", 8);
Font font_1("Sans serif", 10);
std::vector<Font> input_fonts;
- input_fonts.push_back(font.DeriveFont(0, Font::BOLD));
- input_fonts.push_back(font_1.DeriveFont(-2, Font::BOLD));
+ input_fonts.push_back(font.Derive(0, Font::BOLD));
+ input_fonts.push_back(font_1.Derive(-2, Font::BOLD));
FontList font_list = FontList(input_fonts);
const std::vector<Font>& fonts = font_list.GetFonts();
EXPECT_EQ(2U, fonts.size());
@@ -161,8 +168,8 @@ TEST(FontListTest, Fonts_FontVector_RoundTrip) {
Font font("Arial", 8);
Font font_1("Sans serif", 10);
std::vector<Font> input_fonts;
- input_fonts.push_back(font.DeriveFont(0, Font::BOLD));
- input_fonts.push_back(font_1.DeriveFont(-2, Font::BOLD));
+ input_fonts.push_back(font.Derive(0, Font::BOLD));
+ input_fonts.push_back(font_1.Derive(-2, Font::BOLD));
FontList font_list = FontList(input_fonts);
const std::string& desc_string = font_list.GetFontDescriptionString();
@@ -194,71 +201,54 @@ TEST(FontListTest, Fonts_GetStyle) {
fonts.push_back(gfx::Font("Sans serif", 8));
FontList font_list = FontList(fonts);
EXPECT_EQ(Font::NORMAL, font_list.GetFontStyle());
- fonts[0] = fonts[0].DeriveFont(0, Font::ITALIC | Font::BOLD);
- fonts[1] = fonts[1].DeriveFont(0, Font::ITALIC | Font::BOLD);
+ fonts[0] = fonts[0].Derive(0, Font::ITALIC | Font::BOLD);
+ fonts[1] = fonts[1].Derive(0, Font::ITALIC | Font::BOLD);
font_list = FontList(fonts);
EXPECT_EQ(Font::ITALIC | Font::BOLD, font_list.GetFontStyle());
}
-TEST(FontListTest, FontDescString_DeriveFontList) {
- FontList font_list = FontList("Arial,Sans serif, 8px");
-
- FontList derived = font_list.DeriveFontList(Font::BOLD | Font::ITALIC);
- EXPECT_EQ("Arial,Sans serif,Bold Italic 8px",
- derived.GetFontDescriptionString());
-}
-
-TEST(FontListTest, Fonts_DeriveFontList) {
- std::vector<Font> fonts;
- fonts.push_back(gfx::Font("Arial", 8));
- fonts.push_back(gfx::Font("Sans serif", 8));
- FontList font_list = FontList(fonts);
-
- FontList derived = font_list.DeriveFontList(Font::BOLD | Font::ITALIC);
- const std::vector<Font>& derived_fonts = derived.GetFonts();
-
- EXPECT_EQ(2U, derived_fonts.size());
- EXPECT_EQ("Arial|8|bold|italic", FontToString(derived_fonts[0]));
- EXPECT_EQ("Sans serif|8|bold|italic", FontToString(derived_fonts[1]));
-}
+TEST(FontListTest, FontDescString_Derive) {
+ FontList font_list = FontList("Arial,Sans serif,Bold Italic 8px");
-TEST(FontListTest, FontDescString_DeriveFontListWithSize) {
- FontList font_list = FontList("Arial,Sans serif,Bold Italic 8px");
+ FontList derived = font_list.Derive(10, Font::ITALIC | Font::UNDERLINE);
+ EXPECT_EQ("Arial,Sans serif,Italic 18px", derived.GetFontDescriptionString());
+ EXPECT_EQ(Font::ITALIC | Font::UNDERLINE, derived.GetFontStyle());
- FontList derived = font_list.DeriveFontListWithSize(10);
- EXPECT_EQ("Arial,Sans serif,Bold Italic 10px",
- derived.GetFontDescriptionString());
+ // FontList has a special case for Font::UNDERLINE. See if the handling of
+ // Font::UNDERLINE in GetFonts() is okay or not.
+ derived.GetFonts();
+ EXPECT_EQ(Font::ITALIC | Font::UNDERLINE, derived.GetFontStyle());
}
-TEST(FontListTest, Fonts_DeriveFontListWithSize) {
+TEST(FontListTest, Fonts_Derive) {
std::vector<Font> fonts;
fonts.push_back(gfx::Font("Arial", 8));
fonts.push_back(gfx::Font("Sans serif", 8));
FontList font_list = FontList(fonts);
- FontList derived = font_list.DeriveFontListWithSize(5);
+ FontList derived = font_list.Derive(5, Font::BOLD | Font::UNDERLINE);
const std::vector<Font>& derived_fonts = derived.GetFonts();
EXPECT_EQ(2U, derived_fonts.size());
- EXPECT_EQ("Arial|5", FontToString(derived_fonts[0]));
- EXPECT_EQ("Sans serif|5", FontToString(derived_fonts[1]));
+ EXPECT_EQ("Arial|13|bold|underline", FontToString(derived_fonts[0]));
+ EXPECT_EQ("Sans serif|13|bold|underline", FontToString(derived_fonts[1]));
}
-TEST(FontListTest, FontDescString_DeriveFontListWithSizeDelta) {
+TEST(FontListTest, FontDescString_DeriveWithSizeDelta) {
FontList font_list = FontList("Arial,Sans serif,Bold 18px");
- FontList derived = font_list.DeriveFontListWithSizeDelta(-8);
+ FontList derived = font_list.DeriveWithSizeDelta(-8);
EXPECT_EQ("Arial,Sans serif,Bold 10px",
derived.GetFontDescriptionString());
}
-TEST(FontListTest, Fonts_DeriveFontListWithSizeDelta) {
+TEST(FontListTest, Fonts_DeriveWithSizeDelta) {
std::vector<Font> fonts;
- fonts.push_back(gfx::Font("Arial", 18).DeriveFont(0, Font::ITALIC));
- fonts.push_back(gfx::Font("Sans serif", 18).DeriveFont(0, Font::ITALIC));
+ fonts.push_back(gfx::Font("Arial", 18).Derive(0, Font::ITALIC));
+ fonts.push_back(gfx::Font("Sans serif", 18).Derive(0, Font::ITALIC));
FontList font_list = FontList(fonts);
- FontList derived = font_list.DeriveFontListWithSizeDelta(-5);
+ FontList derived = font_list.DeriveWithSizeDelta(-5);
const std::vector<Font>& derived_fonts = derived.GetFonts();
EXPECT_EQ(2U, derived_fonts.size());
@@ -266,30 +256,6 @@ TEST(FontListTest, Fonts_DeriveFontListWithSizeDelta) {
EXPECT_EQ("Sans serif|13|italic", FontToString(derived_fonts[1]));
}
-TEST(FontListTest, FontDescString_DeriveFontListWithSizeDeltaAndStyle) {
- FontList font_list = FontList("Arial,Sans serif,Bold Italic 8px");
-
- FontList derived =
- font_list.DeriveFontListWithSizeDeltaAndStyle(10, Font::ITALIC);
- EXPECT_EQ("Arial,Sans serif,Italic 18px",
- derived.GetFontDescriptionString());
-}
-
-TEST(FontListTest, Fonts_DeriveFontListWithSizeDeltaAndStyle) {
- std::vector<Font> fonts;
- fonts.push_back(gfx::Font("Arial", 8));
- fonts.push_back(gfx::Font("Sans serif", 8));
- FontList font_list = FontList(fonts);
-
- FontList derived =
- font_list.DeriveFontListWithSizeDeltaAndStyle(5, Font::BOLD);
- const std::vector<Font>& derived_fonts = derived.GetFonts();
-
- EXPECT_EQ(2U, derived_fonts.size());
- EXPECT_EQ("Arial|13|bold", FontToString(derived_fonts[0]));
- EXPECT_EQ("Sans serif|13|bold", FontToString(derived_fonts[1]));
-}
-
TEST(FontListTest, Fonts_GetHeight_GetBaseline) {
// If a font list has only one font, the height and baseline must be the same.
Font font1("Arial", 16);
diff --git a/chromium/ui/gfx/font_render_params_linux.cc b/chromium/ui/gfx/font_render_params_linux.cc
index 2fb369a5d4c..fdef6a9926f 100644
--- a/chromium/ui/gfx/font_render_params_linux.cc
+++ b/chromium/ui/gfx/font_render_params_linux.cc
@@ -6,12 +6,13 @@
#include "base/command_line.h"
#include "base/logging.h"
+#include "ui/gfx/display.h"
#include "ui/gfx/switches.h"
-#if defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
-#else
#include <fontconfig/fontconfig.h>
+
+#if defined(OS_LINUX) && defined(USE_AURA) && !defined(OS_CHROMEOS)
+#include "ui/gfx/linux_font_delegate.h"
#endif
namespace gfx {
@@ -19,67 +20,21 @@ namespace gfx {
namespace {
bool SubpixelPositioningRequested(bool renderer) {
- return CommandLine::ForCurrentProcess()->HasSwitch(
- renderer ?
- switches::kEnableWebkitTextSubpixelPositioning :
- switches::kEnableBrowserTextSubpixelPositioning);
+ const CommandLine* cl = CommandLine::ForCurrentProcess();
+ if (renderer) {
+ // Text rendered by Blink in high-DPI mode is poorly-hinted unless subpixel
+ // positioning is used (as opposed to each glyph being individually snapped
+ // to the pixel grid).
+ return cl->HasSwitch(switches::kEnableWebkitTextSubpixelPositioning) ||
+ (Display::HasForceDeviceScaleFactor() &&
+ Display::GetForcedDeviceScaleFactor() != 1.0);
+ }
+ return cl->HasSwitch(switches::kEnableBrowserTextSubpixelPositioning);
}
// Initializes |params| with the system's default settings. |renderer| is true
// when setting WebKit renderer defaults.
void LoadDefaults(FontRenderParams* params, bool renderer) {
-#if defined(TOOLKIT_GTK)
- params->antialiasing = true;
- // TODO(wangxianzhu): autohinter is now true to keep original behavior
- // of WebKit, but it might not be the best value.
- params->autohinter = true;
- params->use_bitmaps = true;
- params->hinting = FontRenderParams::HINTING_SLIGHT;
- params->subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_NONE;
-
- GtkSettings* gtk_settings = gtk_settings_get_default();
- CHECK(gtk_settings);
- gint gtk_antialias = 0;
- gint gtk_hinting = 0;
- gchar* gtk_hint_style = NULL;
- gchar* gtk_rgba = NULL;
- g_object_get(gtk_settings,
- "gtk-xft-antialias", &gtk_antialias,
- "gtk-xft-hinting", &gtk_hinting,
- "gtk-xft-hintstyle", &gtk_hint_style,
- "gtk-xft-rgba", &gtk_rgba,
- NULL);
-
- // g_object_get() doesn't tell us whether the properties were present or not,
- // but if they aren't (because gnome-settings-daemon isn't running), we'll get
- // NULL values for the strings.
- if (gtk_hint_style && gtk_rgba) {
- params->antialiasing = gtk_antialias;
-
- if (gtk_hinting == 0 || strcmp(gtk_hint_style, "hintnone") == 0)
- params->hinting = FontRenderParams::HINTING_NONE;
- else if (strcmp(gtk_hint_style, "hintslight") == 0)
- params->hinting = FontRenderParams::HINTING_SLIGHT;
- else if (strcmp(gtk_hint_style, "hintmedium") == 0)
- params->hinting = FontRenderParams::HINTING_MEDIUM;
- else if (strcmp(gtk_hint_style, "hintfull") == 0)
- params->hinting = FontRenderParams::HINTING_FULL;
-
- if (strcmp(gtk_rgba, "none") == 0)
- params->subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_NONE;
- else if (strcmp(gtk_rgba, "rgb") == 0)
- params->subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_RGB;
- else if (strcmp(gtk_rgba, "bgr") == 0)
- params->subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_BGR;
- else if (strcmp(gtk_rgba, "vrgb") == 0)
- params->subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_VRGB;
- else if (strcmp(gtk_rgba, "vbgr") == 0)
- params->subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_VBGR;
- }
-
- g_free(gtk_hint_style);
- g_free(gtk_rgba);
-#else
// For non-GTK builds (read: Aura), just use reasonable hardcoded values.
params->antialiasing = true;
params->autohinter = true;
@@ -114,6 +69,14 @@ void LoadDefaults(FontRenderParams* params, bool renderer) {
default:
params->subpixel_rendering = FontRenderParams::SUBPIXEL_RENDERING_NONE;
}
+
+#if defined(OS_LINUX) && defined(USE_AURA) && !defined(OS_CHROMEOS)
+ const LinuxFontDelegate* delegate = LinuxFontDelegate::instance();
+ if (delegate) {
+ params->antialiasing = delegate->UseAntialiasing();
+ params->hinting = delegate->GetHintingStyle();
+ params->subpixel_rendering = delegate->GetSubpixelRenderingStyle();
+ }
#endif
params->subpixel_positioning = SubpixelPositioningRequested(renderer);
diff --git a/chromium/ui/gfx/font_smoothing_win.cc b/chromium/ui/gfx/font_smoothing_win.cc
index b181fb564e8..78309ff3d96 100644
--- a/chromium/ui/gfx/font_smoothing_win.cc
+++ b/chromium/ui/gfx/font_smoothing_win.cc
@@ -36,7 +36,7 @@ class CachedFontSmoothingSettings : public gfx::SingletonHwnd::Observer {
// Queries the font settings from the system.
void QueryFontSettings();
- // Indicates whether the MessagePumpObserver has been registered.
+ // Indicates whether the SingletonHwnd::Observer has been registered.
bool observer_added_;
// Indicates whether |smoothing_enabled_| and |cleartype_enabled_| are valid
diff --git a/chromium/ui/gfx/font_unittest.cc b/chromium/ui/gfx/font_unittest.cc
index 2fdaab872f4..da4bdfcc4bd 100644
--- a/chromium/ui/gfx/font_unittest.cc
+++ b/chromium/ui/gfx/font_unittest.cc
@@ -70,7 +70,7 @@ TEST_F(FontTest, LoadArial) {
TEST_F(FontTest, LoadArialBold) {
Font cf("Arial", 16);
- Font bold(cf.DeriveFont(0, Font::BOLD));
+ Font bold(cf.Derive(0, Font::BOLD));
NativeFont native = bold.GetNativeFont();
EXPECT_TRUE(native);
EXPECT_EQ(bold.GetStyle(), Font::BOLD);
@@ -95,11 +95,7 @@ TEST_F(FontTest, CapHeight) {
Font cf("Arial", 16);
EXPECT_GT(cf.GetCapHeight(), 0);
EXPECT_GT(cf.GetCapHeight(), cf.GetHeight() / 2);
-#if defined(OS_CHROMEOS) || defined(OS_LINUX)
- EXPECT_EQ(cf.GetCapHeight(), cf.GetBaseline());
-#else
EXPECT_LT(cf.GetCapHeight(), cf.GetBaseline());
-#endif
}
TEST_F(FontTest, AvgWidths) {
@@ -110,30 +106,26 @@ TEST_F(FontTest, AvgWidths) {
EXPECT_GT(cf.GetExpectedTextWidth(3), cf.GetExpectedTextWidth(2));
}
-TEST_F(FontTest, AvgCharWidth) {
- Font cf("Arial", 16);
- EXPECT_GT(cf.GetAverageCharacterWidth(), 0);
-}
-
-TEST_F(FontTest, Widths) {
- Font cf("Arial", 16);
- EXPECT_EQ(cf.GetStringWidth(base::string16()), 0);
- EXPECT_GT(cf.GetStringWidth(ASCIIToUTF16("a")),
- cf.GetStringWidth(base::string16()));
- EXPECT_GT(cf.GetStringWidth(ASCIIToUTF16("ab")),
- cf.GetStringWidth(ASCIIToUTF16("a")));
- EXPECT_GT(cf.GetStringWidth(ASCIIToUTF16("abc")),
- cf.GetStringWidth(ASCIIToUTF16("ab")));
-}
-
#if !defined(OS_WIN)
// On Windows, Font::GetActualFontNameForTesting() doesn't work well for now.
// http://crbug.com/327287
+//
+// Check that fonts used for testing are installed and enabled. On Mac
+// fonts may be installed but still need enabling in Font Book.app.
+// http://crbug.com/347429
TEST_F(FontTest, GetActualFontNameForTesting) {
Font arial("Arial", 16);
- EXPECT_EQ("arial", StringToLowerASCII(arial.GetActualFontNameForTesting()));
+ EXPECT_EQ("arial", StringToLowerASCII(arial.GetActualFontNameForTesting()))
+ << "********\n"
+ << "Your test environment seems to be missing Arial font, which is "
+ << "needed for unittests. Check if Arial font is installed.\n"
+ << "********";
Font symbol("Symbol", 16);
- EXPECT_EQ("symbol", StringToLowerASCII(symbol.GetActualFontNameForTesting()));
+ EXPECT_EQ("symbol", StringToLowerASCII(symbol.GetActualFontNameForTesting()))
+ << "********\n"
+ << "Your test environment seems to be missing Symbol font, which is "
+ << "needed for unittests. Check if Symbol font is installed.\n"
+ << "********";
const char* const invalid_font_name = "no_such_font_name";
Font fallback_font(invalid_font_name, 16);
@@ -143,21 +135,21 @@ TEST_F(FontTest, GetActualFontNameForTesting) {
#endif
#if defined(OS_WIN)
-TEST_F(FontTest, DeriveFontResizesIfSizeTooSmall) {
+TEST_F(FontTest, DeriveResizesIfSizeTooSmall) {
Font cf("Arial", 8);
// The minimum font size is set to 5 in browser_main.cc.
ScopedMinimumFontSizeCallback minimum_size(5);
- Font derived_font = cf.DeriveFont(-4);
+ Font derived_font = cf.Derive(-4, cf.GetStyle());
EXPECT_EQ(5, derived_font.GetFontSize());
}
-TEST_F(FontTest, DeriveFontKeepsOriginalSizeIfHeightOk) {
+TEST_F(FontTest, DeriveKeepsOriginalSizeIfHeightOk) {
Font cf("Arial", 8);
// The minimum font size is set to 5 in browser_main.cc.
ScopedMinimumFontSizeCallback minimum_size(5);
- Font derived_font = cf.DeriveFont(-2);
+ Font derived_font = cf.Derive(-2, cf.GetStyle());
EXPECT_EQ(6, derived_font.GetFontSize());
}
#endif // defined(OS_WIN)
diff --git a/chromium/ui/gfx/gdi_util.cc b/chromium/ui/gfx/gdi_util.cc
index 88c09355a28..dc7d83f37cf 100644
--- a/chromium/ui/gfx/gdi_util.cc
+++ b/chromium/ui/gfx/gdi_util.cc
@@ -85,8 +85,8 @@ HRGN ConvertPathToHRGN(const gfx::Path& path) {
path.getPoints(points.get(), point_count);
scoped_ptr<POINT[]> windows_points(new POINT[point_count]);
for (int i = 0; i < point_count; ++i) {
- windows_points[i].x = SkScalarRound(points[i].fX);
- windows_points[i].y = SkScalarRound(points[i].fY);
+ windows_points[i].x = SkScalarRoundToInt(points[i].fX);
+ windows_points[i].y = SkScalarRoundToInt(points[i].fY);
}
return ::CreatePolygonRgn(windows_points.get(), point_count, ALTERNATE);
diff --git a/chromium/ui/gfx/gdk_compat.h b/chromium/ui/gfx/gdk_compat.h
deleted file mode 100644
index b11d7795831..00000000000
--- a/chromium/ui/gfx/gdk_compat.h
+++ /dev/null
@@ -1,27 +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_GDK_COMPAT_H_
-#define UI_GFX_GDK_COMPAT_H_
-
-#include <gtk/gtk.h>
-#include <gdk/gdkx.h>
-
-// Google Chrome must depend on GTK 2.18, at least until the next LTS drops
-// (and we might have to extend which version of GTK we want to target due to
-// RHEL). To make our porting job for GTK3 easier, we define all the methods
-// that replace deprecated APIs in this file and then include it everywhere.
-//
-// This file is organized first by version, and then with each version,
-// alphabetically by method.
-
-#if !GTK_CHECK_VERSION(2, 24, 0)
-inline GdkWindow* gdk_x11_window_lookup_for_display(GdkDisplay* display,
- Window window) {
- return static_cast<GdkWindow*>(gdk_xid_table_lookup_for_display(display,
- window));
-}
-#endif
-
-#endif // UI_GFX_GDK_COMPAT_H_
diff --git a/chromium/ui/gfx/geometry/BUILD.gn b/chromium/ui/gfx/geometry/BUILD.gn
new file mode 100644
index 00000000000..b7c877ac108
--- /dev/null
+++ b/chromium/ui/gfx/geometry/BUILD.gn
@@ -0,0 +1,62 @@
+# 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.
+
+component("geometry") {
+ sources = [
+ "../gfx_export.h",
+ "box_f.cc",
+ "box_f.h",
+ "cubic_bezier.h",
+ "cubic_bezier.cc",
+ "insets.cc",
+ "insets.h",
+ "insets_base.h",
+ "insets_f.cc",
+ "insets_f.h",
+ "matrix3_f.cc",
+ "matrix3_f.h",
+ "point.cc",
+ "point.h",
+ "point3_f.cc",
+ "point3_f.h",
+ "point_base.h",
+ "point_conversions.cc",
+ "point_conversions.h",
+ "point_f.cc",
+ "point_f.h",
+ "quad_f.cc",
+ "quad_f.h",
+ "rect.cc",
+ "rect.h",
+ "rect_base.h",
+ "rect_base_impl.h",
+ "rect_conversions.cc",
+ "rect_conversions.h",
+ "rect_f.cc",
+ "rect_f.h",
+ "safe_integer_conversions.h",
+ "size.cc",
+ "size.h",
+ "size_base.h",
+ "size_conversions.cc",
+ "size_conversions.h",
+ "size_f.cc",
+ "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 = [ "GFX_IMPLEMENTATION" ]
+
+ deps = [
+ "//base",
+ "//ui/gfx:gfx_export",
+ ]
+}
diff --git a/chromium/ui/gfx/box_f.cc b/chromium/ui/gfx/geometry/box_f.cc
index 62e755bdc3e..674bb509c88 100644
--- a/chromium/ui/gfx/box_f.cc
+++ b/chromium/ui/gfx/geometry/box_f.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/box_f.h"
+#include "ui/gfx/geometry/box_f.h"
#include <algorithm>
diff --git a/chromium/ui/gfx/geometry/box_f.h b/chromium/ui/gfx/geometry/box_f.h
new file mode 100644
index 00000000000..13fb9d0d47b
--- /dev/null
+++ b/chromium/ui/gfx/geometry/box_f.h
@@ -0,0 +1,160 @@
+// 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_GEOMETRY_BOX_F_H_
+#define UI_GFX_GEOMETRY_BOX_F_H_
+
+#include "ui/gfx/geometry/point3_f.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+
+namespace gfx {
+
+// A 3d version of gfx::RectF, with the positive z-axis pointed towards
+// the camera.
+class GFX_EXPORT BoxF {
+ public:
+ BoxF()
+ : width_(0.f),
+ height_(0.f),
+ depth_(0.f) {}
+
+ BoxF(float width, float height, float depth)
+ : width_(width < 0 ? 0 : width),
+ height_(height < 0 ? 0 : height),
+ depth_(depth < 0 ? 0 : depth) {}
+
+ BoxF(float x, float y, float z, float width, float height, float depth)
+ : origin_(x, y, z),
+ width_(width < 0 ? 0 : width),
+ height_(height < 0 ? 0 : height),
+ depth_(depth < 0 ? 0 : depth) {}
+
+ BoxF(const Point3F& origin, float width, float height, float depth)
+ : origin_(origin),
+ width_(width < 0 ? 0 : width),
+ height_(height < 0 ? 0 : height),
+ depth_(depth < 0 ? 0 : depth) {}
+
+ ~BoxF() {}
+
+ // Scales all three axes by the given scale.
+ void Scale(float scale) {
+ Scale(scale, scale, scale);
+ }
+
+ // Scales each axis by the corresponding given scale.
+ void Scale(float x_scale, float y_scale, float z_scale) {
+ origin_.Scale(x_scale, y_scale, z_scale);
+ set_size(width_ * x_scale, height_ * y_scale, depth_ * z_scale);
+ }
+
+ // Moves the box by the specified distance in each dimension.
+ void operator+=(const Vector3dF& offset) {
+ origin_ += offset;
+ }
+
+ // Returns true if the box has no interior points.
+ bool IsEmpty() const;
+
+ // Computes the union of this box with the given box. The union is the
+ // smallest box that contains both boxes.
+ void Union(const BoxF& box);
+
+ std::string ToString() const;
+
+ float x() const { return origin_.x(); }
+ void set_x(float x) { origin_.set_x(x); }
+
+ float y() const { return origin_.y(); }
+ void set_y(float y) { origin_.set_y(y); }
+
+ float z() const { return origin_.z(); }
+ void set_z(float z) { origin_.set_z(z); }
+
+ float width() const { return width_; }
+ void set_width(float width) { width_ = width < 0 ? 0 : width; }
+
+ float height() const { return height_; }
+ void set_height(float height) { height_ = height < 0 ? 0 : height; }
+
+ float depth() const { return depth_; }
+ void set_depth(float depth) { depth_ = depth < 0 ? 0 : depth; }
+
+ float right() const { return x() + width(); }
+ float bottom() const { return y() + height(); }
+ float front() const { return z() + depth(); }
+
+ void set_size(float width, float height, float depth) {
+ width_ = width < 0 ? 0 : width;
+ height_ = height < 0 ? 0 : height;
+ depth_ = depth < 0 ? 0 : depth;
+ }
+
+ const Point3F& origin() const { return origin_; }
+ void set_origin(const Point3F& origin) { origin_ = origin; }
+
+ // Expands |this| to contain the given point, if necessary. Please note, even
+ // if |this| is empty, after the function |this| will continue to contain its
+ // |origin_|.
+ void ExpandTo(const Point3F& point);
+
+ // Expands |this| to contain the given box, if necessary. Please note, even
+ // if |this| is empty, after the function |this| will continue to contain its
+ // |origin_|.
+ void ExpandTo(const BoxF& box);
+
+ private:
+ // Expands the box to contain the two given points. It is required that each
+ // component of |min| is less than or equal to the corresponding component in
+ // |max|. Precisely, what this function does is ensure that after the function
+ // completes, |this| contains origin_, min, max, and origin_ + (width_,
+ // height_, depth_), even if the box is empty. Emptiness checks are handled in
+ // the public function Union.
+ void ExpandTo(const Point3F& min, const Point3F& max);
+
+ Point3F origin_;
+ float width_;
+ float height_;
+ float depth_;
+};
+
+GFX_EXPORT BoxF UnionBoxes(const BoxF& a, const BoxF& b);
+
+inline BoxF ScaleBox(const BoxF& b,
+ float x_scale,
+ float y_scale,
+ float z_scale) {
+ return BoxF(b.x() * x_scale,
+ b.y() * y_scale,
+ b.z() * z_scale,
+ b.width() * x_scale,
+ b.height() * y_scale,
+ b.depth() * z_scale);
+}
+
+inline BoxF ScaleBox(const BoxF& b, float scale) {
+ return ScaleBox(b, scale, scale, scale);
+}
+
+inline bool operator==(const BoxF& a, const BoxF& b) {
+ return a.origin() == b.origin() && a.width() == b.width() &&
+ a.height() == b.height() && a.depth() == b.depth();
+}
+
+inline bool operator!=(const BoxF& a, const BoxF& b) {
+ return !(a == b);
+}
+
+inline BoxF operator+(const BoxF& b, const Vector3dF& v) {
+ return BoxF(b.x() + v.x(),
+ b.y() + v.y(),
+ b.z() + v.z(),
+ b.width(),
+ b.height(),
+ b.depth());
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_BOX_F_H_
diff --git a/chromium/ui/gfx/box_unittest.cc b/chromium/ui/gfx/geometry/box_unittest.cc
index db894cae1cd..449c50f9a48 100644
--- a/chromium/ui/gfx/box_unittest.cc
+++ b/chromium/ui/gfx/geometry/box_unittest.cc
@@ -4,7 +4,7 @@
#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/box_f.h"
+#include "ui/gfx/geometry/box_f.h"
namespace gfx {
diff --git a/chromium/ui/gfx/geometry/cubic_bezier.cc b/chromium/ui/gfx/geometry/cubic_bezier.cc
new file mode 100644
index 00000000000..3d7e8fe9303
--- /dev/null
+++ b/chromium/ui/gfx/geometry/cubic_bezier.cc
@@ -0,0 +1,128 @@
+// 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/geometry/cubic_bezier.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "base/logging.h"
+
+namespace gfx {
+
+namespace {
+
+static const double kBezierEpsilon = 1e-7;
+static const int MAX_STEPS = 30;
+
+static double eval_bezier(double x1, double x2, double t) {
+ const double x1_times_3 = 3.0 * x1;
+ const double x2_times_3 = 3.0 * x2;
+ const double h3 = x1_times_3;
+ const double h1 = x1_times_3 - x2_times_3 + 1.0;
+ const double h2 = x2_times_3 - 6.0 * x1;
+ return t * (t * (t * h1 + h2) + h3);
+}
+
+static double bezier_interp(double x1,
+ double y1,
+ double x2,
+ double y2,
+ double x) {
+ DCHECK_GE(1.0, x1);
+ DCHECK_LE(0.0, x1);
+ DCHECK_GE(1.0, x2);
+ DCHECK_LE(0.0, x2);
+
+ x1 = std::min(std::max(x1, 0.0), 1.0);
+ x2 = std::min(std::max(x2, 0.0), 1.0);
+ x = std::min(std::max(x, 0.0), 1.0);
+
+ // Step 1. Find the t corresponding to the given x. I.e., we want t such that
+ // eval_bezier(x1, x2, t) = x. There is a unique solution if x1 and x2 lie
+ // within (0, 1).
+ //
+ // We're just going to do bisection for now (for simplicity), but we could
+ // easily do some newton steps if this turns out to be a bottleneck.
+ double t = 0.0;
+ double step = 1.0;
+ for (int i = 0; i < MAX_STEPS; ++i, step *= 0.5) {
+ const double error = eval_bezier(x1, x2, t) - x;
+ if (std::abs(error) < kBezierEpsilon)
+ break;
+ t += error > 0.0 ? -step : step;
+ }
+
+ // We should have terminated the above loop because we got close to x, not
+ // because we exceeded MAX_STEPS. Do a DCHECK here to confirm.
+ DCHECK_GT(kBezierEpsilon, std::abs(eval_bezier(x1, x2, t) - x));
+
+ // Step 2. Return the interpolated y values at the t we computed above.
+ return eval_bezier(y1, y2, t);
+}
+
+} // namespace
+
+CubicBezier::CubicBezier(double x1, double y1, double x2, double y2)
+ : x1_(x1),
+ y1_(y1),
+ x2_(x2),
+ y2_(y2) {
+}
+
+CubicBezier::~CubicBezier() {
+}
+
+double CubicBezier::Solve(double x) const {
+ return bezier_interp(x1_, y1_, x2_, y2_, x);
+}
+
+void CubicBezier::Range(double* min, double* max) const {
+ *min = 0;
+ *max = 1;
+ if (0 <= y1_ && y1_ < 1 && 0 <= y2_ && y2_ <= 1)
+ return;
+
+ // Represent the function's derivative in the form at^2 + bt + c.
+ double a = 3 * (y1_ - y2_) + 1;
+ double b = 2 * (y2_ - 2 * y1_);
+ double c = y1_;
+
+ // Check if the derivative is constant.
+ if (std::abs(a) < kBezierEpsilon &&
+ std::abs(b) < kBezierEpsilon)
+ return;
+
+ // Zeros of the function's derivative.
+ double t_1 = 0;
+ double t_2 = 0;
+
+ if (std::abs(a) < kBezierEpsilon) {
+ // The function's derivative is linear.
+ t_1 = -c / b;
+ } else {
+ // The function's derivative is a quadratic. We find the zeros of this
+ // quadratic using the quadratic formula.
+ double discriminant = b * b - 4 * a * c;
+ if (discriminant < 0)
+ return;
+ double discriminant_sqrt = sqrt(discriminant);
+ t_1 = (-b + discriminant_sqrt) / (2 * a);
+ t_2 = (-b - discriminant_sqrt) / (2 * a);
+ }
+
+ double sol_1 = 0;
+ double sol_2 = 0;
+
+ if (0 < t_1 && t_1 < 1)
+ sol_1 = eval_bezier(y1_, y2_, t_1);
+
+ if (0 < t_2 && t_2 < 1)
+ sol_2 = eval_bezier(y1_, y2_, t_2);
+
+ *min = std::min(std::min(*min, sol_1), sol_2);
+ *max = std::max(std::max(*max, sol_1), sol_2);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/cubic_bezier.h b/chromium/ui/gfx/geometry/cubic_bezier.h
new file mode 100644
index 00000000000..645dfb7106d
--- /dev/null
+++ b/chromium/ui/gfx/geometry/cubic_bezier.h
@@ -0,0 +1,36 @@
+// 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_GEOMETRY_CUBIC_BEZIER_H_
+#define UI_GFX_GEOMETRY_CUBIC_BEZIER_H_
+
+#include "base/macros.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+class GFX_EXPORT CubicBezier {
+ public:
+ CubicBezier(double x1, double y1, double x2, double y2);
+ ~CubicBezier();
+
+ // Returns an approximation of y at the given x.
+ double Solve(double x) const;
+
+ // Sets |min| and |max| to the bezier's minimum and maximium y values in the
+ // interval [0, 1].
+ void Range(double* min, double* max) const;
+
+ private:
+ double x1_;
+ double y1_;
+ double x2_;
+ double y2_;
+
+ DISALLOW_ASSIGN(CubicBezier);
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_CUBIC_BEZIER_H_
diff --git a/chromium/ui/gfx/geometry/cubic_bezier_unittest.cc b/chromium/ui/gfx/geometry/cubic_bezier_unittest.cc
new file mode 100644
index 00000000000..4fd60e87825
--- /dev/null
+++ b/chromium/ui/gfx/geometry/cubic_bezier_unittest.cc
@@ -0,0 +1,140 @@
+// 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/geometry/cubic_bezier.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gfx {
+namespace {
+
+TEST(CubicBezierTest, Basic) {
+ CubicBezier function(0.25, 0.0, 0.75, 1.0);
+
+ double epsilon = 0.00015;
+
+ EXPECT_NEAR(function.Solve(0), 0, epsilon);
+ EXPECT_NEAR(function.Solve(0.05), 0.01136, epsilon);
+ EXPECT_NEAR(function.Solve(0.1), 0.03978, epsilon);
+ EXPECT_NEAR(function.Solve(0.15), 0.079780, epsilon);
+ EXPECT_NEAR(function.Solve(0.2), 0.12803, epsilon);
+ EXPECT_NEAR(function.Solve(0.25), 0.18235, epsilon);
+ EXPECT_NEAR(function.Solve(0.3), 0.24115, epsilon);
+ EXPECT_NEAR(function.Solve(0.35), 0.30323, epsilon);
+ EXPECT_NEAR(function.Solve(0.4), 0.36761, epsilon);
+ EXPECT_NEAR(function.Solve(0.45), 0.43345, epsilon);
+ EXPECT_NEAR(function.Solve(0.5), 0.5, epsilon);
+ EXPECT_NEAR(function.Solve(0.6), 0.63238, epsilon);
+ EXPECT_NEAR(function.Solve(0.65), 0.69676, epsilon);
+ EXPECT_NEAR(function.Solve(0.7), 0.75884, epsilon);
+ EXPECT_NEAR(function.Solve(0.75), 0.81764, epsilon);
+ EXPECT_NEAR(function.Solve(0.8), 0.87196, epsilon);
+ EXPECT_NEAR(function.Solve(0.85), 0.92021, epsilon);
+ EXPECT_NEAR(function.Solve(0.9), 0.96021, epsilon);
+ EXPECT_NEAR(function.Solve(0.95), 0.98863, epsilon);
+ EXPECT_NEAR(function.Solve(1), 1, epsilon);
+}
+
+// Tests that solving the bezier works with knots with y not in (0, 1).
+TEST(CubicBezierTest, UnclampedYValues) {
+ CubicBezier function(0.5, -1.0, 0.5, 2.0);
+
+ double epsilon = 0.00015;
+
+ EXPECT_NEAR(function.Solve(0.0), 0.0, epsilon);
+ EXPECT_NEAR(function.Solve(0.05), -0.08954, epsilon);
+ EXPECT_NEAR(function.Solve(0.1), -0.15613, epsilon);
+ EXPECT_NEAR(function.Solve(0.15), -0.19641, epsilon);
+ EXPECT_NEAR(function.Solve(0.2), -0.20651, epsilon);
+ EXPECT_NEAR(function.Solve(0.25), -0.18232, epsilon);
+ EXPECT_NEAR(function.Solve(0.3), -0.11992, epsilon);
+ EXPECT_NEAR(function.Solve(0.35), -0.01672, epsilon);
+ EXPECT_NEAR(function.Solve(0.4), 0.12660, epsilon);
+ EXPECT_NEAR(function.Solve(0.45), 0.30349, epsilon);
+ EXPECT_NEAR(function.Solve(0.5), 0.50000, epsilon);
+ EXPECT_NEAR(function.Solve(0.55), 0.69651, epsilon);
+ EXPECT_NEAR(function.Solve(0.6), 0.87340, epsilon);
+ EXPECT_NEAR(function.Solve(0.65), 1.01672, epsilon);
+ EXPECT_NEAR(function.Solve(0.7), 1.11992, epsilon);
+ EXPECT_NEAR(function.Solve(0.75), 1.18232, epsilon);
+ EXPECT_NEAR(function.Solve(0.8), 1.20651, epsilon);
+ EXPECT_NEAR(function.Solve(0.85), 1.19641, epsilon);
+ EXPECT_NEAR(function.Solve(0.9), 1.15613, epsilon);
+ EXPECT_NEAR(function.Solve(0.95), 1.08954, epsilon);
+ EXPECT_NEAR(function.Solve(1.0), 1.0, epsilon);
+}
+
+TEST(CubicBezierTest, Range) {
+ double epsilon = 0.00015;
+ double min, max;
+
+ // Derivative is a constant.
+ scoped_ptr<CubicBezier> function(
+ new CubicBezier(0.25, (1.0 / 3.0), 0.75, (2.0 / 3.0)));
+ function->Range(&min, &max);
+ EXPECT_EQ(0, min);
+ EXPECT_EQ(1, max);
+
+ // Derivative is linear.
+ function.reset(new CubicBezier(0.25, -0.5, 0.75, (-1.0 / 6.0)));
+ function->Range(&min, &max);
+ EXPECT_NEAR(min, -0.225, epsilon);
+ EXPECT_EQ(1, max);
+
+ // Derivative has no real roots.
+ function.reset(new CubicBezier(0.25, 0.25, 0.75, 0.5));
+ function->Range(&min, &max);
+ EXPECT_EQ(0, min);
+ EXPECT_EQ(1, max);
+
+ // Derivative has exactly one real root.
+ function.reset(new CubicBezier(0.0, 1.0, 1.0, 0.0));
+ function->Range(&min, &max);
+ EXPECT_EQ(0, min);
+ EXPECT_EQ(1, max);
+
+ // Derivative has one root < 0 and one root > 1.
+ function.reset(new CubicBezier(0.25, 0.1, 0.75, 0.9));
+ function->Range(&min, &max);
+ EXPECT_EQ(0, min);
+ EXPECT_EQ(1, max);
+
+ // Derivative has two roots in [0,1].
+ function.reset(new CubicBezier(0.25, 2.5, 0.75, 0.5));
+ function->Range(&min, &max);
+ EXPECT_EQ(0, min);
+ EXPECT_NEAR(max, 1.28818, epsilon);
+ function.reset(new CubicBezier(0.25, 0.5, 0.75, -1.5));
+ function->Range(&min, &max);
+ EXPECT_NEAR(min, -0.28818, epsilon);
+ EXPECT_EQ(1, max);
+
+ // Derivative has one root < 0 and one root in [0,1].
+ function.reset(new CubicBezier(0.25, 0.1, 0.75, 1.5));
+ function->Range(&min, &max);
+ EXPECT_EQ(0, min);
+ EXPECT_NEAR(max, 1.10755, epsilon);
+
+ // Derivative has one root in [0,1] and one root > 1.
+ function.reset(new CubicBezier(0.25, -0.5, 0.75, 0.9));
+ function->Range(&min, &max);
+ EXPECT_NEAR(min, -0.10755, epsilon);
+ EXPECT_EQ(1, max);
+
+ // Derivative has two roots < 0.
+ function.reset(new CubicBezier(0.25, 0.3, 0.75, 0.633));
+ function->Range(&min, &max);
+ EXPECT_EQ(0, min);
+ EXPECT_EQ(1, max);
+
+ // Derivative has two roots > 1.
+ function.reset(new CubicBezier(0.25, 0.367, 0.75, 0.7));
+ function->Range(&min, &max);
+ EXPECT_EQ(0.f, min);
+ EXPECT_EQ(1.f, max);
+}
+
+} // namespace
+} // namespace gfx
diff --git a/chromium/ui/gfx/insets.cc b/chromium/ui/gfx/geometry/insets.cc
index 44a29916acf..c29368e1bd9 100644
--- a/chromium/ui/gfx/insets.cc
+++ b/chromium/ui/gfx/geometry/insets.cc
@@ -2,11 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/insets.h"
-
-#if defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
-#endif
+#include "ui/gfx/geometry/insets.h"
#include "base/strings/stringprintf.h"
@@ -19,15 +15,6 @@ Insets::Insets() : InsetsBase<Insets, int>(0, 0, 0, 0) {}
Insets::Insets(int top, int left, int bottom, int right)
: InsetsBase<Insets, int>(top, left, bottom, right) {}
-#if defined(TOOLKIT_GTK)
-Insets::Insets(const GtkBorder& border)
- : InsetsBase<Insets, int>(border.top,
- border.left,
- border.bottom,
- border.right) {
-}
-#endif
-
Insets::~Insets() {}
std::string Insets::ToString() const {
diff --git a/chromium/ui/gfx/geometry/insets.h b/chromium/ui/gfx/geometry/insets.h
new file mode 100644
index 00000000000..00b612540dd
--- /dev/null
+++ b/chromium/ui/gfx/geometry/insets.h
@@ -0,0 +1,50 @@
+// 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_INSETS_H_
+#define UI_GFX_GEOMETRY_INSETS_H_
+
+#include <string>
+
+#include "build/build_config.h"
+#include "ui/gfx/geometry/insets_base.h"
+#include "ui/gfx/geometry/insets_f.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// An integer version of gfx::Insets.
+class GFX_EXPORT Insets : public InsetsBase<Insets, int> {
+ public:
+ Insets();
+ Insets(int top, int left, int bottom, int right);
+
+ ~Insets();
+
+ Insets Scale(float scale) const {
+ return Scale(scale, scale);
+ }
+
+ Insets Scale(float x_scale, float y_scale) const {
+ return Insets(static_cast<int>(top() * y_scale),
+ static_cast<int>(left() * x_scale),
+ static_cast<int>(bottom() * y_scale),
+ static_cast<int>(right() * x_scale));
+ }
+
+ operator InsetsF() const {
+ return InsetsF(top(), left(), bottom(), right());
+ }
+
+ // Returns a string representation of the insets.
+ std::string ToString() const;
+};
+
+#if !defined(COMPILER_MSVC)
+extern template class InsetsBase<Insets, int>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_INSETS_H_
diff --git a/chromium/ui/gfx/insets_base.h b/chromium/ui/gfx/geometry/insets_base.h
index da7aca103e5..751d5c11d9b 100644
--- a/chromium/ui/gfx/insets_base.h
+++ b/chromium/ui/gfx/geometry/insets_base.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_INSETS_BASE_H_
-#define UI_GFX_INSETS_BASE_H_
+#ifndef UI_GFX_GEOMETRY_INSETS_BASE_H_
+#define UI_GFX_GEOMETRY_INSETS_BASE_H_
#include "ui/gfx/gfx_export.h"
@@ -77,4 +77,4 @@ class GFX_EXPORT InsetsBase {
} // namespace gfx
-#endif // UI_GFX_INSETS_BASE_H_
+#endif // UI_GFX_GEOMETRY_INSETS_BASE_H_
diff --git a/chromium/ui/gfx/insets_f.cc b/chromium/ui/gfx/geometry/insets_f.cc
index f790b3c4187..774b4ab8ca8 100644
--- a/chromium/ui/gfx/insets_f.cc
+++ b/chromium/ui/gfx/geometry/insets_f.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/insets_f.h"
+#include "ui/gfx/geometry/insets_f.h"
#include "base/strings/stringprintf.h"
diff --git a/chromium/ui/gfx/geometry/insets_f.h b/chromium/ui/gfx/geometry/insets_f.h
new file mode 100644
index 00000000000..ac3585a5a59
--- /dev/null
+++ b/chromium/ui/gfx/geometry/insets_f.h
@@ -0,0 +1,33 @@
+// 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_INSETS_F_H_
+#define UI_GFX_GEOMETRY_INSETS_F_H_
+
+#include <string>
+
+#include "build/build_config.h"
+#include "ui/gfx/geometry/insets_base.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// A floating versin of gfx::Insets.
+class GFX_EXPORT InsetsF : public InsetsBase<InsetsF, float> {
+ public:
+ InsetsF();
+ InsetsF(float top, float left, float bottom, float right);
+ ~InsetsF();
+
+ // Returns a string representation of the insets.
+ std::string ToString() const;
+};
+
+#if !defined(COMPILER_MSVC)
+extern template class InsetsBase<InsetsF, float>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_INSETS_F_H_
diff --git a/chromium/ui/gfx/insets_unittest.cc b/chromium/ui/gfx/geometry/insets_unittest.cc
index 563f20fca23..b20a9d36f48 100644
--- a/chromium/ui/gfx/insets_unittest.cc
+++ b/chromium/ui/gfx/geometry/insets_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/insets.h"
+#include "ui/gfx/geometry/insets.h"
#include "testing/gtest/include/gtest/gtest.h"
diff --git a/chromium/ui/gfx/matrix3_f.cc b/chromium/ui/gfx/geometry/matrix3_f.cc
index 562fdb3a964..5836ae677b9 100644
--- a/chromium/ui/gfx/matrix3_f.cc
+++ b/chromium/ui/gfx/geometry/matrix3_f.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/matrix3_f.h"
+#include "ui/gfx/geometry/matrix3_f.h"
#include <algorithm>
#include <cmath>
diff --git a/chromium/ui/gfx/geometry/matrix3_f.h b/chromium/ui/gfx/geometry/matrix3_f.h
new file mode 100644
index 00000000000..7e43496fd71
--- /dev/null
+++ b/chromium/ui/gfx/geometry/matrix3_f.h
@@ -0,0 +1,108 @@
+// 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.
+
+#ifndef UI_GFX_GEOMETRY_MATRIX3_F_H_
+#define UI_GFX_GEOMETRY_MATRIX3_F_H_
+
+#include "base/logging.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+
+namespace gfx {
+
+class GFX_EXPORT Matrix3F {
+ public:
+ ~Matrix3F();
+
+ static Matrix3F Zeros();
+ static Matrix3F Ones();
+ static Matrix3F Identity();
+ static Matrix3F FromOuterProduct(const Vector3dF& a, const Vector3dF& bt);
+
+ bool IsEqual(const Matrix3F& rhs) const;
+
+ // Element-wise comparison with given precision.
+ bool IsNear(const Matrix3F& rhs, float precision) const;
+
+ float get(int i, int j) const {
+ return data_[MatrixToArrayCoords(i, j)];
+ }
+
+ void set(int i, int j, float v) {
+ data_[MatrixToArrayCoords(i, j)] = v;
+ }
+
+ void set(float m00, float m01, float m02,
+ float m10, float m11, float m12,
+ float m20, float m21, float m22) {
+ data_[0] = m00;
+ data_[1] = m01;
+ data_[2] = m02;
+ data_[3] = m10;
+ data_[4] = m11;
+ data_[5] = m12;
+ data_[6] = m20;
+ data_[7] = m21;
+ data_[8] = m22;
+ }
+
+ Vector3dF get_column(int i) const {
+ return Vector3dF(
+ data_[MatrixToArrayCoords(0, i)],
+ data_[MatrixToArrayCoords(1, i)],
+ data_[MatrixToArrayCoords(2, i)]);
+ }
+
+ void set_column(int i, const Vector3dF& c) {
+ data_[MatrixToArrayCoords(0, i)] = c.x();
+ data_[MatrixToArrayCoords(1, i)] = c.y();
+ data_[MatrixToArrayCoords(2, i)] = c.z();
+ }
+
+ // Returns an inverse of this if the matrix is non-singular, zero (== Zero())
+ // otherwise.
+ Matrix3F Inverse() const;
+
+ // Value of the determinant of the matrix.
+ float Determinant() const;
+
+ // Trace (sum of diagonal elements) of the matrix.
+ float Trace() const {
+ return data_[MatrixToArrayCoords(0, 0)] +
+ data_[MatrixToArrayCoords(1, 1)] +
+ data_[MatrixToArrayCoords(2, 2)];
+ }
+
+ // Compute eigenvalues and (optionally) normalized eigenvectors of
+ // a positive defnite matrix *this. Eigenvectors are computed only if
+ // non-null |eigenvectors| matrix is passed. If it is NULL, the routine
+ // will not attempt to compute eigenvectors but will still return eigenvalues
+ // if they can be computed.
+ // If eigenvalues cannot be computed (the matrix does not meet constraints)
+ // the 0-vector is returned. Note that to retrieve eigenvalues, the matrix
+ // only needs to be symmetric while eigenvectors require it to be
+ // positive-definite. Passing a non-positive definite matrix will result in
+ // NaNs in vectors which cannot be computed.
+ // Eigenvectors are placed as column in |eigenvectors| in order corresponding
+ // to eigenvalues.
+ Vector3dF SolveEigenproblem(Matrix3F* eigenvectors) const;
+
+ private:
+ Matrix3F(); // Uninitialized default.
+
+ static int MatrixToArrayCoords(int i, int j) {
+ DCHECK(i >= 0 && i < 3);
+ DCHECK(j >= 0 && j < 3);
+ return i * 3 + j;
+ }
+
+ float data_[9];
+};
+
+inline bool operator==(const Matrix3F& lhs, const Matrix3F& rhs) {
+ return lhs.IsEqual(rhs);
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_MATRIX3_F_H_
diff --git a/chromium/ui/gfx/matrix3_unittest.cc b/chromium/ui/gfx/geometry/matrix3_unittest.cc
index 04c656f6d26..0f57e8e7a95 100644
--- a/chromium/ui/gfx/matrix3_unittest.cc
+++ b/chromium/ui/gfx/geometry/matrix3_unittest.cc
@@ -7,7 +7,7 @@
#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/matrix3_f.h"
+#include "ui/gfx/geometry/matrix3_f.h"
namespace gfx {
namespace {
diff --git a/chromium/ui/gfx/point.cc b/chromium/ui/gfx/geometry/point.cc
index 7fdf3560fe3..5a68ba67bdd 100644
--- a/chromium/ui/gfx/point.cc
+++ b/chromium/ui/gfx/geometry/point.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/point.h"
+#include "ui/gfx/geometry/point.h"
#if defined(OS_WIN)
#include <windows.h>
diff --git a/chromium/ui/gfx/geometry/point.h b/chromium/ui/gfx/geometry/point.h
new file mode 100644
index 00000000000..ff99d71d361
--- /dev/null
+++ b/chromium/ui/gfx/geometry/point.h
@@ -0,0 +1,90 @@
+// 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_H_
+#define UI_GFX_GEOMETRY_POINT_H_
+
+#include "ui/gfx/geometry/point_base.h"
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/gfx_export.h"
+
+#if defined(OS_WIN)
+typedef unsigned long DWORD;
+typedef struct tagPOINT POINT;
+#elif defined(OS_IOS)
+#include <CoreGraphics/CoreGraphics.h>
+#elif defined(OS_MACOSX)
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+namespace gfx {
+
+// A point has an x and y coordinate.
+class GFX_EXPORT Point : public PointBase<Point, int, Vector2d> {
+ public:
+ Point() : PointBase<Point, int, Vector2d>(0, 0) {}
+ Point(int x, int y) : PointBase<Point, int, Vector2d>(x, y) {}
+#if defined(OS_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 defined(OS_MACOSX)
+ explicit Point(const CGPoint& point);
+#endif
+
+ ~Point() {}
+
+#if defined(OS_WIN)
+ POINT ToPOINT() const;
+#elif defined(OS_MACOSX)
+ CGPoint ToCGPoint() const;
+#endif
+
+ operator PointF() const {
+ return PointF(x(), y());
+ }
+
+ // Returns a string representation of point.
+ std::string ToString() const;
+};
+
+inline bool operator==(const Point& lhs, const Point& rhs) {
+ return lhs.x() == rhs.x() && lhs.y() == rhs.y();
+}
+
+inline bool operator!=(const Point& lhs, const Point& rhs) {
+ return !(lhs == rhs);
+}
+
+inline Point operator+(const Point& lhs, const Vector2d& rhs) {
+ Point result(lhs);
+ result += rhs;
+ return result;
+}
+
+inline Point operator-(const Point& lhs, const Vector2d& rhs) {
+ Point result(lhs);
+ result -= rhs;
+ return result;
+}
+
+inline Vector2d operator-(const Point& lhs, const Point& rhs) {
+ return Vector2d(lhs.x() - rhs.x(), lhs.y() - rhs.y());
+}
+
+inline Point PointAtOffsetFromOrigin(const Vector2d& offset_from_origin) {
+ return Point(offset_from_origin.x(), offset_from_origin.y());
+}
+
+#if !defined(COMPILER_MSVC)
+extern template class PointBase<Point, int, Vector2d>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_POINT_H_
diff --git a/chromium/ui/gfx/point3_f.cc b/chromium/ui/gfx/geometry/point3_f.cc
index 70089a46c21..465376e55e8 100644
--- a/chromium/ui/gfx/point3_f.cc
+++ b/chromium/ui/gfx/geometry/point3_f.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/point3_f.h"
+#include "ui/gfx/geometry/point3_f.h"
#include "base/strings/stringprintf.h"
diff --git a/chromium/ui/gfx/geometry/point3_f.h b/chromium/ui/gfx/geometry/point3_f.h
new file mode 100644
index 00000000000..45bae6e8d32
--- /dev/null
+++ b/chromium/ui/gfx/geometry/point3_f.h
@@ -0,0 +1,120 @@
+// Copyright (c) 2011 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_POINT3_F_H_
+#define UI_GFX_GEOMETRY_POINT3_F_H_
+
+#include <string>
+
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/vector3d_f.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// A point has an x, y and z coordinate.
+class GFX_EXPORT Point3F {
+ public:
+ Point3F() : x_(0), y_(0), z_(0) {}
+
+ Point3F(float x, float y, float z) : x_(x), y_(y), z_(z) {}
+
+ 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 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_; }
+
+ void set_x(float x) { x_ = x; }
+ void set_y(float y) { y_ = y; }
+ void set_z(float z) { z_ = z; }
+
+ void SetPoint(float x, float y, float z) {
+ x_ = x;
+ y_ = y;
+ z_ = z;
+ }
+
+ // 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_;
+ float dy = y_ - other.y_;
+ float dz = z_ - other.z_;
+ return dx * dx + dy * dy + dz * dz;
+ }
+
+ PointF AsPointF() const { return PointF(x_, y_); }
+
+ // Returns a string representation of 3d point.
+ std::string ToString() const;
+
+ private:
+ float x_;
+ float y_;
+ float z_;
+
+ // copy/assign are allowed.
+};
+
+inline bool operator==(const Point3F& lhs, const Point3F& rhs) {
+ return lhs.x() == rhs.x() && lhs.y() == rhs.y() && lhs.z() == rhs.z();
+}
+
+inline bool operator!=(const Point3F& lhs, const Point3F& rhs) {
+ return !(lhs == rhs);
+}
+
+// Add a vector to a point, producing a new point offset by the vector.
+GFX_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.
+GFX_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.
+GFX_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, float scale) {
+ return ScalePoint(p, scale, scale, scale);
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_POINT3_F_H_
diff --git a/chromium/ui/gfx/point3_unittest.cc b/chromium/ui/gfx/geometry/point3_unittest.cc
index 735ffd55425..77f20d79963 100644
--- a/chromium/ui/gfx/point3_unittest.cc
+++ b/chromium/ui/gfx/geometry/point3_unittest.cc
@@ -2,10 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/point3_f.h"
-
#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/point3_f.h"
namespace gfx {
diff --git a/chromium/ui/gfx/point_base.h b/chromium/ui/gfx/geometry/point_base.h
index d7a3951913e..6db1c0cf916 100644
--- a/chromium/ui/gfx/point_base.h
+++ b/chromium/ui/gfx/geometry/point_base.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_POINT_BASE_H_
-#define UI_GFX_POINT_BASE_H_
+#ifndef UI_GFX_GEOMETRY_POINT_BASE_H_
+#define UI_GFX_GEOMETRY_POINT_BASE_H_
#include <string>
@@ -84,4 +84,4 @@ class GFX_EXPORT PointBase {
} // namespace gfx
-#endif // UI_GFX_POINT_BASE_H_
+#endif // UI_GFX_GEOMETRY_POINT_BASE_H_
diff --git a/chromium/ui/gfx/point_conversions.cc b/chromium/ui/gfx/geometry/point_conversions.cc
index f7845a03f41..0613e7a9db1 100644
--- a/chromium/ui/gfx/point_conversions.cc
+++ b/chromium/ui/gfx/geometry/point_conversions.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/point_conversions.h"
+#include "ui/gfx/geometry/point_conversions.h"
-#include "ui/gfx/safe_integer_conversions.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
namespace gfx {
diff --git a/chromium/ui/gfx/geometry/point_conversions.h b/chromium/ui/gfx/geometry/point_conversions.h
new file mode 100644
index 00000000000..bfab9e4e463
--- /dev/null
+++ b/chromium/ui/gfx/geometry/point_conversions.h
@@ -0,0 +1,24 @@
+// 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_CONVERSIONS_H_
+#define UI_GFX_GEOMETRY_POINT_CONVERSIONS_H_
+
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_f.h"
+
+namespace gfx {
+
+// Returns a Point with each component from the input PointF floored.
+GFX_EXPORT Point ToFlooredPoint(const PointF& point);
+
+// Returns a Point with each component from the input PointF ceiled.
+GFX_EXPORT Point ToCeiledPoint(const PointF& point);
+
+// Returns a Point with each component from the input PointF rounded.
+GFX_EXPORT Point ToRoundedPoint(const PointF& point);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_POINT_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/point_f.cc b/chromium/ui/gfx/geometry/point_f.cc
index 21028565d99..9c2ece23a59 100644
--- a/chromium/ui/gfx/point_f.cc
+++ b/chromium/ui/gfx/geometry/point_f.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/point_f.h"
+#include "ui/gfx/geometry/point_f.h"
#include "base/strings/stringprintf.h"
diff --git a/chromium/ui/gfx/geometry/point_f.h b/chromium/ui/gfx/geometry/point_f.h
new file mode 100644
index 00000000000..00266d311d0
--- /dev/null
+++ b/chromium/ui/gfx/geometry/point_f.h
@@ -0,0 +1,75 @@
+// 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_F_H_
+#define UI_GFX_GEOMETRY_POINT_F_H_
+
+#include <string>
+
+#include "ui/gfx/geometry/point_base.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// A floating version of gfx::Point.
+class GFX_EXPORT PointF : public PointBase<PointF, float, Vector2dF> {
+ public:
+ PointF() : PointBase<PointF, float, Vector2dF>(0, 0) {}
+ PointF(float x, float y) : PointBase<PointF, float, Vector2dF>(x, y) {}
+ ~PointF() {}
+
+ void Scale(float scale) {
+ Scale(scale, scale);
+ }
+
+ void Scale(float x_scale, float y_scale) {
+ SetPoint(x() * x_scale, y() * y_scale);
+ }
+
+ // Returns a string representation of point.
+ std::string ToString() const;
+};
+
+inline 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) {
+ return !(lhs == rhs);
+}
+
+inline PointF operator+(const PointF& lhs, const Vector2dF& rhs) {
+ PointF result(lhs);
+ result += rhs;
+ return result;
+}
+
+inline PointF operator-(const PointF& lhs, const Vector2dF& rhs) {
+ PointF result(lhs);
+ result -= rhs;
+ return result;
+}
+
+inline Vector2dF operator-(const PointF& lhs, const PointF& rhs) {
+ return Vector2dF(lhs.x() - rhs.x(), lhs.y() - rhs.y());
+}
+
+inline PointF PointAtOffsetFromOrigin(const Vector2dF& offset_from_origin) {
+ return PointF(offset_from_origin.x(), offset_from_origin.y());
+}
+
+GFX_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);
+}
+
+#if !defined(COMPILER_MSVC)
+extern template class PointBase<PointF, float, Vector2dF>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_POINT_F_H_
diff --git a/chromium/ui/gfx/point_unittest.cc b/chromium/ui/gfx/geometry/point_unittest.cc
index 6cf73dd2adb..8c5f552f89c 100644
--- a/chromium/ui/gfx/point_unittest.cc
+++ b/chromium/ui/gfx/geometry/point_unittest.cc
@@ -2,13 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/point_base.h"
-
#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/point_conversions.h"
-#include "ui/gfx/point_f.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/point_base.h"
+#include "ui/gfx/geometry/point_conversions.h"
+#include "ui/gfx/geometry/point_f.h"
namespace gfx {
diff --git a/chromium/ui/gfx/quad_f.cc b/chromium/ui/gfx/geometry/quad_f.cc
index 2796bf192b2..dbc50458b3f 100644
--- a/chromium/ui/gfx/quad_f.cc
+++ b/chromium/ui/gfx/geometry/quad_f.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/quad_f.h"
+#include "ui/gfx/geometry/quad_f.h"
#include <limits>
@@ -62,28 +62,24 @@ static inline bool PointIsInTriangle(const PointF& point,
const PointF& r1,
const PointF& r2,
const PointF& r3) {
- // Compute the barycentric coordinates of |point| relative to the triangle
- // (r1, r2, r3). This algorithm comes from Christer Ericson's Real-Time
- // Collision Detection.
- Vector2dF v0 = r2 - r1;
- Vector2dF v1 = r3 - r1;
- Vector2dF v2 = point - r1;
+ // 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.
- double dot00 = DotProduct(v0, v0);
- double dot01 = DotProduct(v0, v1);
- double dot11 = DotProduct(v1, v1);
- double dot20 = DotProduct(v2, v0);
- double dot21 = DotProduct(v2, v1);
+ Vector2dF r31 = r1 - r3;
+ Vector2dF r32 = r2 - r3;
+ Vector2dF r3p = point - r3;
- double denom = dot00 * dot11 - dot01 * dot01;
-
- double v = (dot11 * dot20 - dot01 * dot21) / denom;
- double w = (dot00 * dot21 - dot01 * dot20) / denom;
- double u = 1 - v - w;
+ float denom = r32.y() * r31.x() - r32.x() * r31.y();
+ float u = (r32.y() * r3p.x() - r32.x() * r3p.y()) / denom;
+ float v = (r31.x() * r3p.y() - r31.y() * r3p.x()) / denom;
+ float w = 1.f - u - v;
// Use the barycentric coordinates to test if |point| is inside the
// triangle (r1, r2, r2).
- return (v >= 0) && (w >= 0) && (u >= 0);
+ return (u >= 0) && (v >= 0) && (w >= 0);
}
bool QuadF::Contains(const PointF& point) const {
diff --git a/chromium/ui/gfx/geometry/quad_f.h b/chromium/ui/gfx/geometry/quad_f.h
new file mode 100644
index 00000000000..25f8b2b34b3
--- /dev/null
+++ b/chromium/ui/gfx/geometry/quad_f.h
@@ -0,0 +1,109 @@
+// 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_QUAD_F_H_
+#define UI_GFX_GEOMETRY_QUAD_F_H_
+
+#include <algorithm>
+#include <cmath>
+#include <string>
+
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// A Quad is defined by four corners, allowing it to have edges that are not
+// axis-aligned, unlike a Rect.
+class GFX_EXPORT QuadF {
+ public:
+ QuadF() {}
+ QuadF(const PointF& p1, const PointF& p2, const PointF& p3, const PointF& p4)
+ : p1_(p1),
+ p2_(p2),
+ p3_(p3),
+ p4_(p4) {}
+
+ explicit QuadF(const RectF& rect)
+ : p1_(rect.x(), rect.y()),
+ p2_(rect.right(), rect.y()),
+ p3_(rect.right(), rect.bottom()),
+ p4_(rect.x(), rect.bottom()) {}
+
+ void operator=(const RectF& rect);
+
+ void set_p1(const PointF& p) { p1_ = p; }
+ void set_p2(const PointF& p) { p2_ = p; }
+ void set_p3(const PointF& p) { p3_ = p; }
+ void set_p4(const PointF& p) { p4_ = p; }
+
+ const PointF& p1() const { return p1_; }
+ const PointF& p2() const { return p2_; }
+ const PointF& p3() const { return p3_; }
+ const PointF& p4() const { return p4_; }
+
+ // Returns true if the quad is an axis-aligned rectangle.
+ bool IsRectilinear() const;
+
+ // Returns true if the points of the quad are in counter-clockwise order. This
+ // assumes that the quad is convex, and that no three points are collinear.
+ bool IsCounterClockwise() const;
+
+ // 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;
+
+ // 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,
+ // rather than being strictly inside it.
+ RectF BoundingBox() const {
+ float rl = std::min(std::min(p1_.x(), p2_.x()), std::min(p3_.x(), p4_.x()));
+ float rr = std::max(std::max(p1_.x(), p2_.x()), std::max(p3_.x(), p4_.x()));
+ float rt = std::min(std::min(p1_.y(), p2_.y()), std::min(p3_.y(), p4_.y()));
+ float rb = std::max(std::max(p1_.y(), p2_.y()), std::max(p3_.y(), p4_.y()));
+ return RectF(rl, rt, rr - rl, rb - rt);
+ }
+
+ // Add a vector to the quad, offseting each point in the quad by the vector.
+ void operator+=(const Vector2dF& rhs);
+ // Subtract a vector from the quad, offseting each point in the quad by the
+ // inverse of the vector.
+ void operator-=(const Vector2dF& rhs);
+
+ // Scale each point in the quad by the |scale| factor.
+ void Scale(float scale) { Scale(scale, scale); }
+
+ // Scale each point in the quad by the scale factors along each axis.
+ void Scale(float x_scale, float y_scale);
+
+ // Returns a string representation of quad.
+ std::string ToString() const;
+
+ private:
+ PointF p1_;
+ PointF p2_;
+ PointF p3_;
+ PointF p4_;
+};
+
+inline bool operator==(const QuadF& lhs, const QuadF& rhs) {
+ return
+ lhs.p1() == rhs.p1() && lhs.p2() == rhs.p2() &&
+ lhs.p3() == rhs.p3() && lhs.p4() == rhs.p4();
+}
+
+inline bool operator!=(const QuadF& lhs, const QuadF& rhs) {
+ return !(lhs == rhs);
+}
+
+// Add a vector to a quad, offseting each point in the quad by the vector.
+GFX_EXPORT QuadF operator+(const QuadF& lhs, const Vector2dF& rhs);
+// Subtract a vector from a quad, offseting each point in the quad by the
+// inverse of the vector.
+GFX_EXPORT QuadF operator-(const QuadF& lhs, const Vector2dF& rhs);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_QUAD_F_H_
diff --git a/chromium/ui/gfx/quad_unittest.cc b/chromium/ui/gfx/geometry/quad_unittest.cc
index 8859a0e6972..6ba2b51813e 100644
--- a/chromium/ui/gfx/quad_unittest.cc
+++ b/chromium/ui/gfx/geometry/quad_unittest.cc
@@ -2,11 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/quad_f.h"
-
#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/rect_f.h"
+#include "ui/gfx/geometry/quad_f.h"
+#include "ui/gfx/geometry/rect_f.h"
namespace gfx {
diff --git a/chromium/ui/gfx/geometry/r_tree.h b/chromium/ui/gfx/geometry/r_tree.h
new file mode 100644
index 00000000000..53fd5c9f900
--- /dev/null
+++ b/chromium/ui/gfx/geometry/r_tree.h
@@ -0,0 +1,182 @@
+// 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.
+
+// Defines a hierarchical bounding rectangle data structure for Rect objects,
+// associated with a generic unique key K for efficient spatial queries. The
+// R*-tree algorithm is used to build the trees. Based on the papers:
+//
+// A Guttman 'R-trees: a dynamic index structure for spatial searching', Proc
+// ACM SIGMOD Int Conf on Management of Data, 47-57, 1984
+//
+// N Beckmann, H-P Kriegel, R Schneider, B Seeger 'The R*-tree: an efficient and
+// robust access method for points and rectangles', Proc ACM SIGMOD Int Conf on
+// Management of Data, 322-331, 1990
+
+#ifndef UI_GFX_GEOMETRY_R_TREE_H_
+#define UI_GFX_GEOMETRY_R_TREE_H_
+
+#include "r_tree_base.h"
+
+namespace gfx {
+
+template <typename Key>
+class RTree : public RTreeBase {
+ public:
+ typedef base::hash_set<Key> Matches;
+
+ // RTrees organize pairs of keys and rectangles in a hierarchical bounding
+ // box structure. This allows for queries of the tree within logarithmic time.
+ // |min_children| and |max_children| allows for adjustment of the average size
+ // of the nodes within RTree, which adjusts the base of the logarithm in the
+ // algorithm runtime. Some parts of insertion and deletion are polynomial
+ // in the size of the individual node, so the trade-off with larger nodes is
+ // potentially faster queries but slower insertions and deletions. Generally
+ // it is worth considering how much overlap between rectangles of different
+ // keys will occur in the tree, and trying to set |max_children| as a
+ // reasonable upper bound to the number of overlapping rectangles expected.
+ // Then |min_children| can bet set to a quantity slightly less than half of
+ // that.
+ RTree(size_t min_children, size_t max_children);
+ ~RTree();
+
+ // Insert a new rect into the tree, associated with provided key. Note that if
+ // |rect| is empty, the |key| will not actually be inserted. Duplicate keys
+ // overwrite old entries.
+ void Insert(const Rect& rect, Key key);
+
+ // If present, remove the supplied |key| from the tree.
+ void Remove(Key key);
+
+ // Fills |matches_out| with all keys having bounding rects intersecting
+ // |query_rect|.
+ void AppendIntersectingRecords(const Rect& query_rect,
+ Matches* matches_out) const;
+
+ void Clear();
+
+ private:
+ friend class RTreeTest;
+ friend class RTreeNodeTest;
+
+ class Record : public RecordBase {
+ public:
+ Record(const Rect& rect, const Key& key);
+ virtual ~Record();
+ const Key& key() const { return key_; }
+
+ private:
+ Key key_;
+
+ DISALLOW_COPY_AND_ASSIGN(Record);
+ };
+
+ // A map of supplied keys to their Node representation within the RTree, for
+ // efficient retrieval of keys without requiring a bounding rect.
+ typedef base::hash_map<Key, Record*> RecordMap;
+ RecordMap record_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(RTree);
+};
+
+template <typename Key>
+RTree<Key>::RTree(size_t min_children, size_t max_children)
+ : RTreeBase(min_children, max_children) {
+}
+
+template <typename Key>
+RTree<Key>::~RTree() {
+}
+
+template <typename Key>
+void RTree<Key>::Insert(const Rect& rect, Key key) {
+ scoped_ptr<NodeBase> record;
+ // Check if this key is already present in the tree.
+ typename RecordMap::iterator it(record_map_.find(key));
+
+ if (it != record_map_.end()) {
+ // We will re-use this node structure, regardless of re-insert or return.
+ Record* existing_record = it->second;
+ // If the new rect and the current rect are identical we can skip the rest
+ // of Insert() as nothing has changed.
+ if (existing_record->rect() == rect)
+ return;
+
+ // Remove the node from the tree in its current position.
+ record = RemoveNode(existing_record);
+
+ PruneRootIfNecessary();
+
+ // If we are replacing this key with an empty rectangle we just remove the
+ // old node from the list and return, thus preventing insertion of empty
+ // rectangles into our spatial database.
+ if (rect.IsEmpty()) {
+ record_map_.erase(it);
+ return;
+ }
+
+ // Reset the rectangle to the new value.
+ record->set_rect(rect);
+ } else {
+ if (rect.IsEmpty())
+ return;
+
+ record.reset(new Record(rect, key));
+ record_map_.insert(std::make_pair(key, static_cast<Record*>(record.get())));
+ }
+
+ int highest_reinsert_level = -1;
+ InsertNode(record.Pass(), &highest_reinsert_level);
+}
+
+template <typename Key>
+void RTree<Key>::Clear() {
+ record_map_.clear();
+ ResetRoot();
+}
+
+template <typename Key>
+void RTree<Key>::Remove(Key key) {
+ // Search the map for the leaf parent that has the provided record.
+ typename RecordMap::iterator it = record_map_.find(key);
+ if (it == record_map_.end())
+ return;
+
+ Record* record = it->second;
+ record_map_.erase(it);
+ RemoveNode(record);
+
+ // Lastly check the root. If it has only one non-leaf child, delete it and
+ // replace it with its child.
+ PruneRootIfNecessary();
+}
+
+template <typename Key>
+void RTree<Key>::AppendIntersectingRecords(
+ const Rect& query_rect, Matches* matches_out) const {
+ RTreeBase::Records matching_records;
+ root()->AppendIntersectingRecords(query_rect, &matching_records);
+ for (RTreeBase::Records::const_iterator it = matching_records.begin();
+ it != matching_records.end();
+ ++it) {
+ const Record* record = static_cast<const Record*>(*it);
+ matches_out->insert(record->key());
+ }
+}
+
+
+// RTree::Record --------------------------------------------------------------
+
+template <typename Key>
+RTree<Key>::Record::Record(const Rect& rect, const Key& key)
+ : RecordBase(rect),
+ key_(key) {
+}
+
+template <typename Key>
+RTree<Key>::Record::~Record() {
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_R_TREE_H_
diff --git a/chromium/ui/gfx/geometry/r_tree_base.cc b/chromium/ui/gfx/geometry/r_tree_base.cc
new file mode 100644
index 00000000000..e93e1d5b6b1
--- /dev/null
+++ b/chromium/ui/gfx/geometry/r_tree_base.cc
@@ -0,0 +1,658 @@
+// 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/geometry/r_tree_base.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+
+
+// Helpers --------------------------------------------------------------------
+
+namespace {
+
+// Returns a Vector2d to allow us to do arithmetic on the result such as
+// computing distances between centers.
+gfx::Vector2d CenterOfRect(const gfx::Rect& rect) {
+ return rect.OffsetFromOrigin() +
+ gfx::Vector2d(rect.width() / 2, rect.height() / 2);
+}
+
+}
+
+namespace gfx {
+
+
+// RTreeBase::NodeBase --------------------------------------------------------
+
+RTreeBase::NodeBase::~NodeBase() {
+}
+
+void RTreeBase::NodeBase::RecomputeBoundsUpToRoot() {
+ RecomputeLocalBounds();
+ if (parent_)
+ parent_->RecomputeBoundsUpToRoot();
+}
+
+RTreeBase::NodeBase::NodeBase(const Rect& rect, NodeBase* parent)
+ : rect_(rect),
+ parent_(parent) {
+}
+
+void RTreeBase::NodeBase::RecomputeLocalBounds() {
+}
+
+// RTreeBase::RecordBase ------------------------------------------------------
+
+RTreeBase::RecordBase::RecordBase(const Rect& rect) : NodeBase(rect, NULL) {
+}
+
+RTreeBase::RecordBase::~RecordBase() {
+}
+
+void RTreeBase::RecordBase::AppendIntersectingRecords(
+ const Rect& query_rect, Records* matches_out) const {
+ if (rect().Intersects(query_rect))
+ matches_out->push_back(this);
+}
+
+void RTreeBase::RecordBase::AppendAllRecords(Records* matches_out) const {
+ matches_out->push_back(this);
+}
+
+scoped_ptr<RTreeBase::NodeBase>
+RTreeBase::RecordBase::RemoveAndReturnLastChild() {
+ return scoped_ptr<NodeBase>();
+}
+
+int RTreeBase::RecordBase::Level() const {
+ return -1;
+}
+
+
+// RTreeBase::Node ------------------------------------------------------------
+
+RTreeBase::Node::Node() : NodeBase(Rect(), NULL), level_(0) {
+}
+
+RTreeBase::Node::~Node() {
+}
+
+scoped_ptr<RTreeBase::Node> RTreeBase::Node::ConstructParent() {
+ DCHECK(!parent());
+ scoped_ptr<Node> new_parent(new Node(level_ + 1));
+ new_parent->AddChild(scoped_ptr<NodeBase>(this));
+ return new_parent.Pass();
+}
+
+void RTreeBase::Node::AppendIntersectingRecords(
+ const Rect& query_rect, Records* matches_out) const {
+ // Check own bounding box for intersection, can cull all children if no
+ // intersection.
+ if (!rect().Intersects(query_rect))
+ return;
+
+ // Conversely if we are completely contained within the query rect we can
+ // confidently skip all bounds checks for ourselves and all our children.
+ if (query_rect.Contains(rect())) {
+ AppendAllRecords(matches_out);
+ return;
+ }
+
+ // We intersect the query rect but we are not are not contained within it.
+ // We must query each of our children in turn.
+ for (Nodes::const_iterator i = children_.begin(); i != children_.end(); ++i)
+ (*i)->AppendIntersectingRecords(query_rect, matches_out);
+}
+
+void RTreeBase::Node::AppendAllRecords(Records* matches_out) const {
+ for (Nodes::const_iterator i = children_.begin(); i != children_.end(); ++i)
+ (*i)->AppendAllRecords(matches_out);
+}
+
+void RTreeBase::Node::RemoveNodesForReinsert(size_t number_to_remove,
+ Nodes* nodes) {
+ DCHECK_LE(number_to_remove, children_.size());
+
+ std::partial_sort(children_.begin(),
+ children_.begin() + number_to_remove,
+ children_.end(),
+ &RTreeBase::Node::CompareCenterDistanceFromParent);
+
+ // Move the lowest-distance nodes to the returned vector.
+ nodes->insert(
+ nodes->end(), children_.begin(), children_.begin() + number_to_remove);
+ children_.weak_erase(children_.begin(), children_.begin() + number_to_remove);
+}
+
+scoped_ptr<RTreeBase::NodeBase> RTreeBase::Node::RemoveChild(
+ NodeBase* child_node, Nodes* orphans) {
+ DCHECK_EQ(this, child_node->parent());
+
+ scoped_ptr<NodeBase> orphan(child_node->RemoveAndReturnLastChild());
+ while (orphan) {
+ orphans->push_back(orphan.release());
+ orphan = child_node->RemoveAndReturnLastChild();
+ }
+
+ Nodes::iterator i = std::find(children_.begin(), children_.end(), child_node);
+ DCHECK(i != children_.end());
+ children_.weak_erase(i);
+
+ return scoped_ptr<NodeBase>(child_node);
+}
+
+scoped_ptr<RTreeBase::NodeBase> RTreeBase::Node::RemoveAndReturnLastChild() {
+ if (children_.empty())
+ return scoped_ptr<NodeBase>();
+
+ scoped_ptr<NodeBase> last_child(children_.back());
+ children_.weak_erase(children_.end() - 1);
+ last_child->set_parent(NULL);
+ return last_child.Pass();
+}
+
+RTreeBase::Node* RTreeBase::Node::ChooseSubtree(NodeBase* node) {
+ DCHECK(node);
+ // Should never be called on a node at equal or lower level in the tree than
+ // the node to insert.
+ DCHECK_GT(level_, node->Level());
+
+ // If we are a parent of nodes on the provided node level, we are done.
+ if (level_ == node->Level() + 1)
+ return this;
+
+ // Precompute a vector of expanded rects, used by both LeastOverlapIncrease
+ // and LeastAreaEnlargement.
+ Rects expanded_rects;
+ expanded_rects.reserve(children_.size());
+ for (Nodes::iterator i = children_.begin(); i != children_.end(); ++i)
+ expanded_rects.push_back(UnionRects(node->rect(), (*i)->rect()));
+
+ Node* best_candidate = NULL;
+ // For parents of leaf nodes, we pick the node that will cause the least
+ // increase in overlap by the addition of this new node. This may detect a
+ // tie, in which case it will return NULL.
+ if (level_ == 1)
+ best_candidate = LeastOverlapIncrease(node->rect(), expanded_rects);
+
+ // For non-parents of leaf nodes, or for parents of leaf nodes with ties in
+ // overlap increase, we choose the subtree with least area enlargement caused
+ // by the addition of the new node.
+ if (!best_candidate)
+ best_candidate = LeastAreaEnlargement(node->rect(), expanded_rects);
+
+ DCHECK(best_candidate);
+ return best_candidate->ChooseSubtree(node);
+}
+
+size_t RTreeBase::Node::AddChild(scoped_ptr<NodeBase> node) {
+ DCHECK(node);
+ // Sanity-check that the level of the child being added is one less than ours.
+ DCHECK_EQ(level_ - 1, node->Level());
+ node->set_parent(this);
+ set_rect(UnionRects(rect(), node->rect()));
+ children_.push_back(node.release());
+ return children_.size();
+}
+
+scoped_ptr<RTreeBase::NodeBase> RTreeBase::Node::Split(size_t min_children,
+ size_t max_children) {
+ // We should have too many children to begin with.
+ DCHECK_EQ(max_children + 1, children_.size());
+
+ // Determine if we should split along the horizontal or vertical axis.
+ std::vector<NodeBase*> vertical_sort(children_.get());
+ std::vector<NodeBase*> horizontal_sort(children_.get());
+ std::sort(vertical_sort.begin(),
+ vertical_sort.end(),
+ &RTreeBase::Node::CompareVertical);
+ std::sort(horizontal_sort.begin(),
+ horizontal_sort.end(),
+ &RTreeBase::Node::CompareHorizontal);
+
+ Rects low_vertical_bounds;
+ Rects low_horizontal_bounds;
+ BuildLowBounds(vertical_sort,
+ horizontal_sort,
+ &low_vertical_bounds,
+ &low_horizontal_bounds);
+
+ Rects high_vertical_bounds;
+ Rects high_horizontal_bounds;
+ BuildHighBounds(vertical_sort,
+ horizontal_sort,
+ &high_vertical_bounds,
+ &high_horizontal_bounds);
+
+ // Choose |end_index| such that both Nodes after the split will have
+ // min_children <= children_.size() <= max_children.
+ size_t end_index = std::min(max_children, children_.size() - min_children);
+ bool is_vertical_split =
+ SmallestMarginSum(min_children,
+ end_index,
+ low_horizontal_bounds,
+ high_horizontal_bounds) <
+ SmallestMarginSum(min_children,
+ end_index,
+ low_vertical_bounds,
+ high_vertical_bounds);
+
+ // Choose split index along chosen axis and perform the split.
+ const Rects& low_bounds(
+ is_vertical_split ? low_vertical_bounds : low_horizontal_bounds);
+ const Rects& high_bounds(
+ is_vertical_split ? high_vertical_bounds : high_horizontal_bounds);
+ size_t split_index =
+ ChooseSplitIndex(min_children, end_index, low_bounds, high_bounds);
+
+ const std::vector<NodeBase*>& sort(
+ is_vertical_split ? vertical_sort : horizontal_sort);
+ return DivideChildren(low_bounds, high_bounds, sort, split_index);
+}
+
+int RTreeBase::Node::Level() const {
+ return level_;
+}
+
+RTreeBase::Node::Node(int level) : NodeBase(Rect(), NULL), level_(level) {
+}
+
+// static
+bool RTreeBase::Node::CompareVertical(const NodeBase* a, const NodeBase* b) {
+ const Rect& a_rect = a->rect();
+ const Rect& b_rect = b->rect();
+ return (a_rect.y() < b_rect.y()) ||
+ ((a_rect.y() == b_rect.y()) && (a_rect.height() < b_rect.height()));
+}
+
+// static
+bool RTreeBase::Node::CompareHorizontal(const NodeBase* a, const NodeBase* b) {
+ const Rect& a_rect = a->rect();
+ const Rect& b_rect = b->rect();
+ return (a_rect.x() < b_rect.x()) ||
+ ((a_rect.x() == b_rect.x()) && (a_rect.width() < b_rect.width()));
+}
+
+// static
+bool RTreeBase::Node::CompareCenterDistanceFromParent(const NodeBase* a,
+ const NodeBase* b) {
+ const NodeBase* p = a->parent();
+
+ DCHECK(p);
+ DCHECK_EQ(p, b->parent());
+
+ Vector2d p_center = CenterOfRect(p->rect());
+ Vector2d a_center = CenterOfRect(a->rect());
+ Vector2d b_center = CenterOfRect(b->rect());
+
+ // We don't bother with square roots because we are only comparing the two
+ // values for sorting purposes.
+ return (a_center - p_center).LengthSquared() <
+ (b_center - p_center).LengthSquared();
+}
+
+// static
+void RTreeBase::Node::BuildLowBounds(
+ const std::vector<NodeBase*>& vertical_sort,
+ const std::vector<NodeBase*>& horizontal_sort,
+ Rects* vertical_bounds,
+ Rects* horizontal_bounds) {
+ Rect vertical_bounds_rect;
+ vertical_bounds->reserve(vertical_sort.size());
+ for (std::vector<NodeBase*>::const_iterator i = vertical_sort.begin();
+ i != vertical_sort.end();
+ ++i) {
+ vertical_bounds_rect.Union((*i)->rect());
+ vertical_bounds->push_back(vertical_bounds_rect);
+ }
+
+ Rect horizontal_bounds_rect;
+ horizontal_bounds->reserve(horizontal_sort.size());
+ for (std::vector<NodeBase*>::const_iterator i = horizontal_sort.begin();
+ i != horizontal_sort.end();
+ ++i) {
+ horizontal_bounds_rect.Union((*i)->rect());
+ horizontal_bounds->push_back(horizontal_bounds_rect);
+ }
+}
+
+// static
+void RTreeBase::Node::BuildHighBounds(
+ const std::vector<NodeBase*>& vertical_sort,
+ const std::vector<NodeBase*>& horizontal_sort,
+ Rects* vertical_bounds,
+ Rects* horizontal_bounds) {
+ Rect vertical_bounds_rect;
+ vertical_bounds->reserve(vertical_sort.size());
+ for (std::vector<NodeBase*>::const_reverse_iterator i =
+ vertical_sort.rbegin();
+ i != vertical_sort.rend();
+ ++i) {
+ vertical_bounds_rect.Union((*i)->rect());
+ vertical_bounds->push_back(vertical_bounds_rect);
+ }
+ std::reverse(vertical_bounds->begin(), vertical_bounds->end());
+
+ Rect horizontal_bounds_rect;
+ horizontal_bounds->reserve(horizontal_sort.size());
+ for (std::vector<NodeBase*>::const_reverse_iterator i =
+ horizontal_sort.rbegin();
+ i != horizontal_sort.rend();
+ ++i) {
+ horizontal_bounds_rect.Union((*i)->rect());
+ horizontal_bounds->push_back(horizontal_bounds_rect);
+ }
+ std::reverse(horizontal_bounds->begin(), horizontal_bounds->end());
+}
+
+size_t RTreeBase::Node::ChooseSplitIndex(size_t start_index,
+ size_t end_index,
+ const Rects& low_bounds,
+ const Rects& high_bounds) {
+ DCHECK_EQ(low_bounds.size(), high_bounds.size());
+
+ int smallest_overlap_area = UnionRects(
+ low_bounds[start_index], high_bounds[start_index]).size().GetArea();
+ int smallest_combined_area = low_bounds[start_index].size().GetArea() +
+ high_bounds[start_index].size().GetArea();
+ size_t optimal_split_index = start_index;
+ for (size_t p = start_index + 1; p < end_index; ++p) {
+ const int overlap_area =
+ UnionRects(low_bounds[p], high_bounds[p]).size().GetArea();
+ const int combined_area =
+ low_bounds[p].size().GetArea() + high_bounds[p].size().GetArea();
+ if ((overlap_area < smallest_overlap_area) ||
+ ((overlap_area == smallest_overlap_area) &&
+ (combined_area < smallest_combined_area))) {
+ smallest_overlap_area = overlap_area;
+ smallest_combined_area = combined_area;
+ optimal_split_index = p;
+ }
+ }
+
+ // optimal_split_index currently points at the last element in the first set,
+ // so advance it by 1 to point at the first element in the second set.
+ return optimal_split_index + 1;
+}
+
+// static
+int RTreeBase::Node::SmallestMarginSum(size_t start_index,
+ size_t end_index,
+ const Rects& low_bounds,
+ const Rects& high_bounds) {
+ DCHECK_EQ(low_bounds.size(), high_bounds.size());
+ DCHECK_LT(start_index, low_bounds.size());
+ DCHECK_LE(start_index, end_index);
+ DCHECK_LE(end_index, low_bounds.size());
+ Rects::const_iterator i(low_bounds.begin() + start_index);
+ Rects::const_iterator j(high_bounds.begin() + start_index);
+ int smallest_sum = i->width() + i->height() + j->width() + j->height();
+ for (; i != (low_bounds.begin() + end_index); ++i, ++j) {
+ smallest_sum = std::min(
+ smallest_sum, i->width() + i->height() + j->width() + j->height());
+ }
+
+ return smallest_sum;
+}
+
+void RTreeBase::Node::RecomputeLocalBounds() {
+ Rect bounds;
+ for (size_t i = 0; i < children_.size(); ++i)
+ bounds.Union(children_[i]->rect());
+
+ set_rect(bounds);
+}
+
+int RTreeBase::Node::OverlapIncreaseToAdd(const Rect& rect,
+ const NodeBase* candidate_node,
+ const Rect& expanded_rect) const {
+ DCHECK(candidate_node);
+
+ // Early-out when |rect| is contained completely within |candidate|.
+ if (candidate_node->rect().Contains(rect))
+ return 0;
+
+ int total_original_overlap = 0;
+ int total_expanded_overlap = 0;
+
+ // Now calculate overlap with all other rects in this node.
+ for (Nodes::const_iterator it = children_.begin();
+ it != children_.end(); ++it) {
+ // Skip calculating overlap with the candidate rect.
+ if ((*it) == candidate_node)
+ continue;
+ NodeBase* overlap_node = (*it);
+ total_original_overlap += IntersectRects(
+ candidate_node->rect(), overlap_node->rect()).size().GetArea();
+ Rect expanded_overlap_rect = expanded_rect;
+ expanded_overlap_rect.Intersect(overlap_node->rect());
+ total_expanded_overlap += expanded_overlap_rect.size().GetArea();
+ }
+
+ return total_expanded_overlap - total_original_overlap;
+}
+
+scoped_ptr<RTreeBase::NodeBase> RTreeBase::Node::DivideChildren(
+ const Rects& low_bounds,
+ const Rects& high_bounds,
+ const std::vector<NodeBase*>& sorted_children,
+ size_t split_index) {
+ DCHECK_EQ(low_bounds.size(), high_bounds.size());
+ DCHECK_EQ(low_bounds.size(), sorted_children.size());
+ DCHECK_LT(split_index, low_bounds.size());
+ DCHECK_GT(split_index, 0U);
+
+ scoped_ptr<Node> sibling(new Node(level_));
+ sibling->set_parent(parent());
+ set_rect(low_bounds[split_index - 1]);
+ sibling->set_rect(high_bounds[split_index]);
+
+ // Our own children_ vector is unsorted, so we wipe it out and divide the
+ // sorted bounds rects between ourselves and our sibling.
+ children_.weak_clear();
+ children_.insert(children_.end(),
+ sorted_children.begin(),
+ sorted_children.begin() + split_index);
+ sibling->children_.insert(sibling->children_.end(),
+ sorted_children.begin() + split_index,
+ sorted_children.end());
+
+ for (size_t i = 0; i < sibling->children_.size(); ++i)
+ sibling->children_[i]->set_parent(sibling.get());
+
+ return sibling.PassAs<NodeBase>();
+}
+
+RTreeBase::Node* RTreeBase::Node::LeastOverlapIncrease(
+ const Rect& node_rect,
+ const Rects& expanded_rects) {
+ NodeBase* best_node = children_.front();
+ int least_overlap_increase =
+ OverlapIncreaseToAdd(node_rect, children_[0], expanded_rects[0]);
+ for (size_t i = 1; i < children_.size(); ++i) {
+ int overlap_increase =
+ OverlapIncreaseToAdd(node_rect, children_[i], expanded_rects[i]);
+ if (overlap_increase < least_overlap_increase) {
+ least_overlap_increase = overlap_increase;
+ best_node = children_[i];
+ } else if (overlap_increase == least_overlap_increase) {
+ // If we are tied at zero there is no possible better overlap increase,
+ // so we can report a tie early.
+ if (overlap_increase == 0)
+ return NULL;
+
+ best_node = NULL;
+ }
+ }
+
+ // Ensure that our children are always Nodes and not Records.
+ DCHECK_GE(level_, 1);
+ return static_cast<Node*>(best_node);
+}
+
+RTreeBase::Node* RTreeBase::Node::LeastAreaEnlargement(
+ const Rect& node_rect,
+ const Rects& expanded_rects) {
+ DCHECK(!children_.empty());
+ DCHECK_EQ(children_.size(), expanded_rects.size());
+
+ NodeBase* best_node = children_.front();
+ int least_area_enlargement =
+ expanded_rects[0].size().GetArea() - best_node->rect().size().GetArea();
+ for (size_t i = 1; i < children_.size(); ++i) {
+ NodeBase* candidate_node = children_[i];
+ int area_change = expanded_rects[i].size().GetArea() -
+ candidate_node->rect().size().GetArea();
+ DCHECK_GE(area_change, 0);
+ if (area_change < least_area_enlargement) {
+ best_node = candidate_node;
+ least_area_enlargement = area_change;
+ } else if (area_change == least_area_enlargement &&
+ candidate_node->rect().size().GetArea() <
+ best_node->rect().size().GetArea()) {
+ // Ties are broken by choosing the entry with the least area.
+ best_node = candidate_node;
+ }
+ }
+
+ // Ensure that our children are always Nodes and not Records.
+ DCHECK_GE(level_, 1);
+ return static_cast<Node*>(best_node);
+}
+
+
+// RTreeBase ------------------------------------------------------------------
+
+RTreeBase::RTreeBase(size_t min_children, size_t max_children)
+ : root_(new Node()),
+ min_children_(min_children),
+ max_children_(max_children) {
+ DCHECK_GE(min_children_, 2U);
+ DCHECK_LE(min_children_, max_children_ / 2U);
+}
+
+RTreeBase::~RTreeBase() {
+}
+
+void RTreeBase::InsertNode(
+ scoped_ptr<NodeBase> node, int* highest_reinsert_level) {
+ // Find the most appropriate parent to insert node into.
+ Node* parent = root_->ChooseSubtree(node.get());
+ DCHECK(parent);
+ // Verify ChooseSubtree returned a Node at the correct level.
+ DCHECK_EQ(parent->Level(), node->Level() + 1);
+ Node* insert_parent = static_cast<Node*>(parent);
+ NodeBase* needs_bounds_recomputed = insert_parent->parent();
+ Nodes reinserts;
+ // Attempt to insert the Node, if this overflows the Node we must handle it.
+ while (insert_parent &&
+ insert_parent->AddChild(node.Pass()) > max_children_) {
+ // If we have yet to re-insert nodes at this level during this data insert,
+ // and we're not at the root, R*-Tree calls for re-insertion of some of the
+ // nodes, resulting in a better balance on the tree.
+ if (insert_parent->parent() &&
+ insert_parent->Level() > *highest_reinsert_level) {
+ insert_parent->RemoveNodesForReinsert(max_children_ / 3, &reinserts);
+ // Adjust highest_reinsert_level to this level.
+ *highest_reinsert_level = insert_parent->Level();
+ // RemoveNodesForReinsert() does not recompute bounds, so mark it.
+ needs_bounds_recomputed = insert_parent;
+ break;
+ }
+
+ // Split() will create a sibling to insert_parent both of which will have
+ // valid bounds, but this invalidates their parent's bounds.
+ node = insert_parent->Split(min_children_, max_children_);
+ insert_parent = static_cast<Node*>(insert_parent->parent());
+ needs_bounds_recomputed = insert_parent;
+ }
+
+ // If we have a Node to insert, and we hit the root of the current tree,
+ // we create a new root which is the parent of the current root and the
+ // insert_node. Note that we must release() the |root_| since
+ // ConstructParent() will take ownership of it.
+ if (!insert_parent && node) {
+ root_ = root_.release()->ConstructParent();
+ root_->AddChild(node.Pass());
+ }
+
+ // Recompute bounds along insertion path.
+ if (needs_bounds_recomputed)
+ needs_bounds_recomputed->RecomputeBoundsUpToRoot();
+
+ // Complete re-inserts, if any. The algorithm only allows for one invocation
+ // of RemoveNodesForReinsert() per level of the tree in an overall call to
+ // Insert().
+ while (!reinserts.empty()) {
+ Nodes::iterator last_element = reinserts.end() - 1;
+ NodeBase* temp_ptr(*last_element);
+ reinserts.weak_erase(last_element);
+ InsertNode(make_scoped_ptr(temp_ptr), highest_reinsert_level);
+ }
+}
+
+scoped_ptr<RTreeBase::NodeBase> RTreeBase::RemoveNode(NodeBase* node) {
+ // We need to remove this node from its parent.
+ Node* parent = static_cast<Node*>(node->parent());
+ // Record nodes are never allowed as the root, so we should always have a
+ // parent.
+ DCHECK(parent);
+ // Should always be a leaf that had the record.
+ DCHECK_EQ(0, parent->Level());
+
+ Nodes orphans;
+ scoped_ptr<NodeBase> removed_node(parent->RemoveChild(node, &orphans));
+
+ // It's possible that by removing |node| from |parent| we have made |parent|
+ // have less than the minimum number of children, in which case we will need
+ // to remove and delete |parent| while reinserting any other children that it
+ // had. We traverse up the tree doing this until we remove a child from a
+ // parent that still has greater than or equal to the minimum number of Nodes.
+ while (parent->count() < min_children_) {
+ NodeBase* child = parent;
+ parent = static_cast<Node*>(parent->parent());
+
+ // If we've hit the root, stop.
+ if (!parent)
+ break;
+
+ parent->RemoveChild(child, &orphans);
+ }
+
+ // If we stopped deleting nodes up the tree before encountering the root,
+ // we'll need to fix up the bounds from the first parent we didn't delete
+ // up to the root.
+ if (parent)
+ parent->RecomputeBoundsUpToRoot();
+ else
+ root_->RecomputeBoundsUpToRoot();
+
+ while (!orphans.empty()) {
+ Nodes::iterator last_element = orphans.end() - 1;
+ NodeBase* temp_ptr(*last_element);
+ orphans.weak_erase(last_element);
+ int starting_level = -1;
+ InsertNode(make_scoped_ptr(temp_ptr), &starting_level);
+ }
+
+ return removed_node.Pass();
+}
+
+void RTreeBase::PruneRootIfNecessary() {
+ if (root()->count() == 1 && root()->Level() > 0) {
+ // Awkward reset(cast(release)) pattern here because there's no better way
+ // to downcast the scoped_ptr from RemoveAndReturnLastChild() from NodeBase
+ // to Node.
+ root_.reset(
+ static_cast<Node*>(root_->RemoveAndReturnLastChild().release()));
+ }
+}
+
+void RTreeBase::ResetRoot() {
+ root_.reset(new Node());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/geometry/r_tree_base.h b/chromium/ui/gfx/geometry/r_tree_base.h
new file mode 100644
index 00000000000..21dc86b2d4d
--- /dev/null
+++ b/chromium/ui/gfx/geometry/r_tree_base.h
@@ -0,0 +1,309 @@
+// 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.
+
+// Provides an implementation the parts of the RTree data structure that don't
+// require knowledge of the generic key type. Don't use these objects directly,
+// rather specialize the RTree<> object in r_tree.h. This file defines the
+// internal objects of an RTree, namely Nodes (internal nodes of the tree) and
+// Records, which hold (key, rectangle) pairs.
+
+#ifndef UI_GFX_GEOMETRY_R_TREE_BASE_H_
+#define UI_GFX_GEOMETRY_R_TREE_BASE_H_
+
+#include <list>
+#include <vector>
+
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+class GFX_EXPORT RTreeBase {
+ protected:
+ class NodeBase;
+ class RecordBase;
+
+ typedef std::vector<const RecordBase*> Records;
+ typedef ScopedVector<NodeBase> Nodes;
+
+ RTreeBase(size_t min_children, size_t max_children);
+ ~RTreeBase();
+
+ // Protected data structure class for storing internal Nodes or leaves with
+ // Records.
+ class GFX_EXPORT NodeBase {
+ public:
+ virtual ~NodeBase();
+
+ // Appends to |records_out| the set of Records in this subtree with rects
+ // that intersect |query_rect|. Avoids clearing |records_out| so that it
+ // can be called recursively.
+ virtual void AppendIntersectingRecords(const Rect& query_rect,
+ Records* records_out) const = 0;
+
+ // Returns all records stored in the subtree rooted at this node. Appends to
+ // |matches_out| without clearing.
+ virtual void AppendAllRecords(Records* records_out) const = 0;
+
+ // Returns NULL if no children. Does not recompute bounds.
+ virtual scoped_ptr<NodeBase> RemoveAndReturnLastChild() = 0;
+
+ // Returns -1 for Records, or the height of this subtree for Nodes. The
+ // height of a leaf Node (a Node containing only Records) is 0, a leaf's
+ // parent is 1, etc. Note that in an R*-Tree, all branches from the root
+ // Node will be the same height.
+ virtual int Level() const = 0;
+
+ // Recomputes our bounds by taking the union of all child rects, then calls
+ // recursively on our parent so that ultimately all nodes up to the root
+ // recompute their bounds.
+ void RecomputeBoundsUpToRoot();
+
+ NodeBase* parent() { return parent_; }
+ const NodeBase* parent() const { return parent_; }
+ void set_parent(NodeBase* parent) { parent_ = parent; }
+ const Rect& rect() const { return rect_; }
+ void set_rect(const Rect& rect) { rect_ = rect; }
+
+ protected:
+ NodeBase(const Rect& rect, NodeBase* parent);
+
+ // Bounds recomputation without calling parents to do the same.
+ virtual void RecomputeLocalBounds();
+
+ private:
+ friend class RTreeTest;
+ friend class RTreeNodeTest;
+
+ // This Node's bounding rectangle.
+ Rect rect_;
+
+ // A weak pointer to our parent Node in the RTree. The root node will have a
+ // NULL value for |parent_|.
+ NodeBase* parent_;
+
+ DISALLOW_COPY_AND_ASSIGN(NodeBase);
+ };
+
+ class GFX_EXPORT RecordBase : public NodeBase {
+ public:
+ explicit RecordBase(const Rect& rect);
+ virtual ~RecordBase();
+
+ virtual void AppendIntersectingRecords(const Rect& query_rect,
+ Records* records_out) const OVERRIDE;
+ virtual void AppendAllRecords(Records* records_out) const OVERRIDE;
+ virtual scoped_ptr<NodeBase> RemoveAndReturnLastChild() OVERRIDE;
+ virtual int Level() const OVERRIDE;
+
+ private:
+ friend class RTreeTest;
+ friend class RTreeNodeTest;
+
+ DISALLOW_COPY_AND_ASSIGN(RecordBase);
+ };
+
+ class GFX_EXPORT Node : public NodeBase {
+ public:
+ // Constructs an empty Node with |level_| of 0.
+ Node();
+ virtual ~Node();
+
+ virtual void AppendIntersectingRecords(const Rect& query_rect,
+ Records* records_out) const OVERRIDE;
+ virtual scoped_ptr<NodeBase> RemoveAndReturnLastChild() OVERRIDE;
+ virtual int Level() const OVERRIDE;
+ virtual void AppendAllRecords(Records* matches_out) const OVERRIDE;
+
+ // Constructs a new Node that is the parent of this Node and already has
+ // this Node as its sole child. Valid to call only on root Nodes, meaning
+ // Nodes with |parent_| NULL. Note that ownership of this Node is
+ // transferred to the parent returned by this function.
+ scoped_ptr<Node> ConstructParent();
+
+ // Removes |number_to_remove| children from this Node, and appends them to
+ // the supplied list. Does not repair bounds upon completion. Nodes are
+ // selected in the manner suggested in the Beckmann et al. paper, which
+ // suggests that the children should be sorted by the distance from the
+ // center of their bounding rectangle to their parent's bounding rectangle,
+ // and then the n closest children should be removed for re-insertion. This
+ // removal occurs at most once on each level of the tree when overflowing
+ // nodes that have exceeded the maximum number of children during an Insert.
+ void RemoveNodesForReinsert(size_t number_to_remove, Nodes* nodes);
+
+ // Given a pointer to a child node within this Node, removes it from our
+ // list. If that child had any children, appends them to the supplied orphan
+ // list. Returns the removed child. Does not recompute bounds, as the caller
+ // might subsequently remove this node as well, meaning the recomputation
+ // would be wasted work.
+ scoped_ptr<NodeBase> RemoveChild(NodeBase* child_node, Nodes* orphans);
+
+ // Returns the best parent for insertion of the provided |node| as a child.
+ Node* ChooseSubtree(NodeBase* node);
+
+ // Adds |node| as a child of this Node, and recomputes the bounds of this
+ // node after the addition of the child. Returns the new count of children
+ // stored in this Node. This node becomes the owner of |node|.
+ size_t AddChild(scoped_ptr<NodeBase> node);
+
+ // Returns a sibling to this Node with at least min_children and no greater
+ // than max_children of this Node's children assigned to it, and having the
+ // same parent. Bounds will be valid on both Nodes after this call.
+ scoped_ptr<NodeBase> Split(size_t min_children, size_t max_children);
+
+ size_t count() const { return children_.size(); }
+ const NodeBase* child(size_t i) const { return children_[i]; }
+ NodeBase* child(size_t i) { return children_[i]; }
+
+ private:
+ typedef std::vector<Rect> Rects;
+
+ explicit Node(int level);
+
+ // Given two arrays of bounds rectangles as computed by BuildLowBounds()
+ // and BuildHighBounds(), returns the index of the element in those arrays
+ // along which a split of the arrays would result in a minimum amount of
+ // overlap (area of intersection) in the two groups.
+ static size_t ChooseSplitIndex(size_t start_index,
+ size_t end_index,
+ const Rects& low_bounds,
+ const Rects& high_bounds);
+
+ // R*-Tree attempts to keep groups of rectangles that are roughly square
+ // in shape. It does this by comparing the "margins" of different bounding
+ // boxes, where margin is defined as the sum of the length of all four sides
+ // of a rectangle. For two rectangles of equal area, the one with the
+ // smallest margin will be the rectangle whose width and height differ the
+ // least. When splitting we decide to split along an axis chosen from the
+ // rectangles either sorted vertically or horizontally by finding the axis
+ // that would result in the smallest sum of margins between the two bounding
+ // boxes of the resulting split. Returns the smallest sum computed given the
+ // sorted bounding boxes and a range to look within.
+ static int SmallestMarginSum(size_t start_index,
+ size_t end_index,
+ const Rects& low_bounds,
+ const Rects& high_bounds);
+
+ // Sorts nodes primarily by increasing y coordinates, and secondarily by
+ // increasing height.
+ static bool CompareVertical(const NodeBase* a, const NodeBase* b);
+
+ // Sorts nodes primarily by increasing x coordinates, and secondarily by
+ // increasing width.
+ static bool CompareHorizontal(const NodeBase* a, const NodeBase* b);
+
+ // Sorts nodes by the distance of the center of their rectangles to the
+ // center of their parent's rectangles.
+ static bool CompareCenterDistanceFromParent(
+ const NodeBase* a, const NodeBase* b);
+
+ // Given two vectors of Nodes sorted by vertical or horizontal bounds,
+ // populates two vectors of Rectangles in which the ith element is the union
+ // of all bounding rectangles [0,i] in the associated sorted array of Nodes.
+ static void BuildLowBounds(const std::vector<NodeBase*>& vertical_sort,
+ const std::vector<NodeBase*>& horizontal_sort,
+ Rects* vertical_bounds,
+ Rects* horizontal_bounds);
+
+ // Given two vectors of Nodes sorted by vertical or horizontal bounds,
+ // populates two vectors of Rectangles in which the ith element is the
+ // union of all bounding rectangles [i, count()) in the associated sorted
+ // array of Nodes.
+ static void BuildHighBounds(const std::vector<NodeBase*>& vertical_sort,
+ const std::vector<NodeBase*>& horizontal_sort,
+ Rects* vertical_bounds,
+ Rects* horizontal_bounds);
+
+ virtual void RecomputeLocalBounds() OVERRIDE;
+
+ // Returns the increase in overlap value, as defined in Beckmann et al. as
+ // the sum of the areas of the intersection of all child rectangles
+ // (excepting the candidate child) with the argument rectangle. Here the
+ // |candidate_node| is one of our |children_|, and |expanded_rect| is the
+ // already-computed union of the candidate's rect and |rect|.
+ int OverlapIncreaseToAdd(const Rect& rect,
+ const NodeBase* candidate_node,
+ const Rect& expanded_rect) const;
+
+ // Returns a new node containing children [split_index, count()) within
+ // |sorted_children|. Children before |split_index| remain with |this|.
+ scoped_ptr<NodeBase> DivideChildren(
+ const Rects& low_bounds,
+ const Rects& high_bounds,
+ const std::vector<NodeBase*>& sorted_children,
+ size_t split_index);
+
+ // Returns a pointer to the child node that will result in the least overlap
+ // increase with the addition of node_rect, or NULL if there's a tie found.
+ // Requires a precomputed vector of expanded rectangles where the ith
+ // rectangle in the vector is the union of |children_|[i] and node_rect.
+ // Overlap is defined in Beckmann et al. as the sum of the areas of
+ // intersection of all child rectangles with the |node_rect| argument
+ // rectangle. This heuristic attempts to choose the node for which adding
+ // the new rectangle to their bounding box will result in the least overlap
+ // with the other rectangles, thus trying to preserve the usefulness of the
+ // bounding rectangle by keeping it from covering too much redundant area.
+ Node* LeastOverlapIncrease(const Rect& node_rect,
+ const Rects& expanded_rects);
+
+ // Returns a pointer to the child node that will result in the least area
+ // enlargement if the argument node rectangle were to be added to that
+ // node's bounding box. Requires a precomputed vector of expanded rectangles
+ // where the ith rectangle in the vector is the union of children_[i] and
+ // |node_rect|.
+ Node* LeastAreaEnlargement(const Rect& node_rect,
+ const Rects& expanded_rects);
+
+ const int level_;
+
+ Nodes children_;
+
+ friend class RTreeTest;
+ friend class RTreeNodeTest;
+
+ DISALLOW_COPY_AND_ASSIGN(Node);
+ };
+
+ // Inserts |node| into the tree. The |highest_reinsert_level| supports
+ // re-insertion as described by Beckmann et al. As Node overflows progagate
+ // up the tree the algorithm performs a reinsertion of the overflow Nodes
+ // (instead of a split) at most once per level of the tree. A starting value
+ // of -1 for |highest_reinsert_level| means that reinserts are permitted for
+ // every level of the tree. This should always be set to -1 except by
+ // recursive calls from within InsertNode().
+ void InsertNode(scoped_ptr<NodeBase> node, int* highest_reinsert_level);
+
+ // Removes |node| from the tree without deleting it.
+ scoped_ptr<NodeBase> RemoveNode(NodeBase* node);
+
+ // If |root_| has only one child, deletes the |root_| Node and replaces it
+ // with its only descendant child. Otherwise does nothing.
+ void PruneRootIfNecessary();
+
+ // Deletes the entire current tree and replaces it with an empty Node.
+ void ResetRoot();
+
+ const Node* root() const { return root_.get(); }
+
+ private:
+ friend class RTreeTest;
+ friend class RTreeNodeTest;
+
+ // A pointer to the root node in the RTree.
+ scoped_ptr<Node> root_;
+
+ // The parameters used to define the shape of the RTree.
+ const size_t min_children_;
+ const size_t max_children_;
+
+ DISALLOW_COPY_AND_ASSIGN(RTreeBase);
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_R_TREE_BASE_H_
diff --git a/chromium/ui/gfx/geometry/r_tree_unittest.cc b/chromium/ui/gfx/geometry/r_tree_unittest.cc
new file mode 100644
index 00000000000..ba45405ee2a
--- /dev/null
+++ b/chromium/ui/gfx/geometry/r_tree_unittest.cc
@@ -0,0 +1,1025 @@
+// 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 "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/r_tree.h"
+#include "ui/gfx/geometry/r_tree_base.h"
+#include "ui/gfx/geometry/rect.h"
+
+namespace gfx {
+
+class RTreeTest : public ::testing::Test {
+ protected:
+ typedef RTree<int> RT;
+
+ // Given a pointer to an RTree, traverse it and verify that its internal
+ // structure is consistent with RTree semantics.
+ void ValidateRTree(RTreeBase* rt) {
+ // If RTree is empty it should have an empty rectangle.
+ if (!rt->root()->count()) {
+ EXPECT_TRUE(rt->root()->rect().IsEmpty());
+ EXPECT_EQ(0, rt->root()->Level());
+ return;
+ }
+ // Root is allowed to have fewer than min_children_ but never more than
+ // max_children_.
+ EXPECT_LE(rt->root()->count(), rt->max_children_);
+ // The root should never be a record node.
+ EXPECT_GT(rt->root()->Level(), -1);
+ // The root should never have a parent pointer.
+ EXPECT_TRUE(rt->root()->parent() == NULL);
+ // Bounds must be consistent on the root.
+ CheckBoundsConsistent(rt->root());
+ for (size_t i = 0; i < rt->root()->count(); ++i) {
+ ValidateNode(
+ rt->root()->child(i), rt->min_children_, rt->max_children_);
+ }
+ }
+
+ // Recursive descent method used by ValidateRTree to check each node within
+ // the RTree for consistency with RTree semantics.
+ void ValidateNode(const RTreeBase::NodeBase* node_base,
+ size_t min_children,
+ size_t max_children) {
+ if (node_base->Level() >= 0) {
+ const RTreeBase::Node* node =
+ static_cast<const RTreeBase::Node*>(node_base);
+ EXPECT_GE(node->count(), min_children);
+ EXPECT_LE(node->count(), max_children);
+ CheckBoundsConsistent(node);
+ for (size_t i = 0; i < node->count(); ++i)
+ ValidateNode(node->child(i), min_children, max_children);
+ }
+ }
+
+ // Check bounds are consistent with children bounds, and other checks
+ // convenient to do while enumerating the children of node.
+ void CheckBoundsConsistent(const RTreeBase::Node* node) {
+ EXPECT_FALSE(node->rect().IsEmpty());
+ Rect check_bounds;
+ for (size_t i = 0; i < node->count(); ++i) {
+ const RTreeBase::NodeBase* child_node = node->child(i);
+ check_bounds.Union(child_node->rect());
+ EXPECT_EQ(node->Level() - 1, child_node->Level());
+ EXPECT_EQ(node, child_node->parent());
+ }
+ EXPECT_EQ(check_bounds, node->rect());
+ }
+
+ // Adds count squares stacked around the point (0,0) with key equal to width.
+ void AddStackedSquares(RT* rt, int count) {
+ for (int i = 1; i <= count; ++i) {
+ rt->Insert(Rect(0, 0, i, i), i);
+ ValidateRTree(static_cast<RTreeBase*>(rt));
+ }
+ }
+
+ // Given an unordered list of matching keys, verifies that it contains all
+ // values [1..length] for the length of that list.
+ void VerifyAllKeys(const RT::Matches& keys) {
+ for (size_t i = 1; i <= keys.size(); ++i)
+ EXPECT_EQ(1U, keys.count(i));
+ }
+
+ // Given a node and a rectangle, builds an expanded rectangle list where the
+ // ith element of the vector is the union of the rectangle of the ith child of
+ // the node and the argument rectangle.
+ void BuildExpandedRects(RTreeBase::Node* node,
+ const Rect& rect,
+ std::vector<Rect>* expanded_rects) {
+ expanded_rects->clear();
+ expanded_rects->reserve(node->count());
+ for (size_t i = 0; i < node->count(); ++i) {
+ Rect expanded_rect(rect);
+ expanded_rect.Union(node->child(i)->rect());
+ expanded_rects->push_back(expanded_rect);
+ }
+ }
+};
+
+class RTreeNodeTest : public RTreeTest {
+ protected:
+ typedef RTreeBase::NodeBase RTreeNodeBase;
+ typedef RT::Record RTreeRecord;
+ typedef RTreeBase::Node RTreeNode;
+ typedef RTreeBase::Node::Rects RTreeRects;
+ typedef RTreeBase::Nodes RTreeNodes;
+
+ // Accessors to private members of RTree::Node.
+ const RTreeRecord* record(RTreeNode* node, size_t i) {
+ return static_cast<const RTreeRecord*>(node->child(i));
+ }
+
+ // Provides access for tests to private methods of RTree::Node.
+ scoped_ptr<RTreeNode> NewNodeAtLevel(size_t level) {
+ return make_scoped_ptr(new RTreeBase::Node(level));
+ }
+
+ void NodeRecomputeLocalBounds(RTreeNodeBase* node) {
+ node->RecomputeLocalBounds();
+ }
+
+ bool NodeCompareVertical(RTreeNodeBase* a, RTreeNodeBase* b) {
+ return RTreeBase::Node::CompareVertical(a, b);
+ }
+
+ bool NodeCompareHorizontal(RTreeNodeBase* a, RTreeNodeBase* b) {
+ return RTreeBase::Node::CompareHorizontal(a, b);
+ }
+
+ bool NodeCompareCenterDistanceFromParent(
+ const RTreeNodeBase* a, const RTreeNodeBase* b) {
+ return RTreeBase::Node::CompareCenterDistanceFromParent(a, b);
+ }
+
+ int NodeOverlapIncreaseToAdd(RTreeNode* node,
+ const Rect& rect,
+ const RTreeNodeBase* candidate_node,
+ const Rect& expanded_rect) {
+ return node->OverlapIncreaseToAdd(rect, candidate_node, expanded_rect);
+ }
+
+ void NodeBuildLowBounds(const std::vector<RTreeNodeBase*>& vertical_sort,
+ const std::vector<RTreeNodeBase*>& horizontal_sort,
+ RTreeRects* vertical_bounds,
+ RTreeRects* horizontal_bounds) {
+ RTreeBase::Node::BuildLowBounds(
+ vertical_sort, horizontal_sort, vertical_bounds, horizontal_bounds);
+ }
+
+ void NodeBuildHighBounds(const std::vector<RTreeNodeBase*>& vertical_sort,
+ const std::vector<RTreeNodeBase*>& horizontal_sort,
+ RTreeRects* vertical_bounds,
+ RTreeRects* horizontal_bounds) {
+ RTreeBase::Node::BuildHighBounds(
+ vertical_sort, horizontal_sort, vertical_bounds, horizontal_bounds);
+ }
+
+ int NodeSmallestMarginSum(size_t start_index,
+ size_t end_index,
+ const RTreeRects& low_bounds,
+ const RTreeRects& high_bounds) {
+ return RTreeBase::Node::SmallestMarginSum(
+ start_index, end_index, low_bounds, high_bounds);
+ }
+
+ size_t NodeChooseSplitIndex(size_t min_children,
+ size_t max_children,
+ const RTreeRects& low_bounds,
+ const RTreeRects& high_bounds) {
+ return RTreeBase::Node::ChooseSplitIndex(
+ min_children, max_children, low_bounds, high_bounds);
+ }
+
+ scoped_ptr<RTreeNodeBase> NodeDivideChildren(
+ RTreeNode* node,
+ const RTreeRects& low_bounds,
+ const RTreeRects& high_bounds,
+ const std::vector<RTreeNodeBase*>& sorted_children,
+ size_t split_index) {
+ return node->DivideChildren(
+ low_bounds, high_bounds, sorted_children, split_index);
+ }
+
+ RTreeNode* NodeLeastOverlapIncrease(RTreeNode* node,
+ const Rect& node_rect,
+ const RTreeRects& expanded_rects) {
+ return node->LeastOverlapIncrease(node_rect, expanded_rects);
+ }
+
+ RTreeNode* NodeLeastAreaEnlargement(RTreeNode* node,
+ const Rect& node_rect,
+ const RTreeRects& expanded_rects) {
+ return node->LeastAreaEnlargement(node_rect, expanded_rects);
+ }
+};
+
+// RTreeNodeTest --------------------------------------------------------------
+
+TEST_F(RTreeNodeTest, RemoveNodesForReinsert) {
+ // Make a leaf node for testing removal from.
+ scoped_ptr<RTreeNode> test_node(new RTreeNode);
+ // Build 20 record nodes with rectangle centers going from (1,1) to (20,20)
+ for (int i = 1; i <= 20; ++i)
+ test_node->AddChild(scoped_ptr<RTreeNodeBase>(
+ new RTreeRecord(Rect(i - 1, i - 1, 2, 2), i)));
+
+ // Quick verification of the node before removing children.
+ ValidateNode(test_node.get(), 1U, 20U);
+ // Use a scoped vector to delete all children that get removed from the Node.
+ RTreeNodes removals;
+ test_node->RemoveNodesForReinsert(1, &removals);
+ // Should have gotten back 1 node pointer.
+ EXPECT_EQ(1U, removals.size());
+ // There should be 19 left in the test_node.
+ EXPECT_EQ(19U, test_node->count());
+ // If we fix up the bounds on the test_node, it should verify.
+ NodeRecomputeLocalBounds(test_node.get());
+ ValidateNode(test_node.get(), 2U, 20U);
+ // The node we removed should be node 10, as it was exactly in the center.
+ EXPECT_EQ(10, static_cast<RTreeRecord*>(removals[0])->key());
+
+ // Now remove the next 2.
+ removals.clear();
+ test_node->RemoveNodesForReinsert(2, &removals);
+ EXPECT_EQ(2U, removals.size());
+ EXPECT_EQ(17U, test_node->count());
+ NodeRecomputeLocalBounds(test_node.get());
+ ValidateNode(test_node.get(), 2U, 20U);
+ // Lastly the 2 nodes we should have gotten back are keys 9 and 11, as their
+ // centers were the closest to the center of the node bounding box.
+ base::hash_set<intptr_t> results_hash;
+ results_hash.insert(static_cast<RTreeRecord*>(removals[0])->key());
+ results_hash.insert(static_cast<RTreeRecord*>(removals[1])->key());
+ EXPECT_EQ(1U, results_hash.count(9));
+ EXPECT_EQ(1U, results_hash.count(11));
+}
+
+TEST_F(RTreeNodeTest, CompareVertical) {
+ // One rect with lower y than another should always sort lower.
+ RTreeRecord low(Rect(0, 1, 10, 10), 1);
+ RTreeRecord middle(Rect(0, 5, 10, 10), 5);
+ EXPECT_TRUE(NodeCompareVertical(&low, &middle));
+ EXPECT_FALSE(NodeCompareVertical(&middle, &low));
+
+ // Try a non-overlapping higher-y rectangle.
+ RTreeRecord high(Rect(-10, 20, 10, 1), 10);
+ EXPECT_TRUE(NodeCompareVertical(&low, &high));
+ EXPECT_FALSE(NodeCompareVertical(&high, &low));
+
+ // Ties are broken by lowest bottom y value.
+ RTreeRecord shorter_tie(Rect(10, 1, 100, 2), 2);
+ EXPECT_TRUE(NodeCompareVertical(&shorter_tie, &low));
+ EXPECT_FALSE(NodeCompareVertical(&low, &shorter_tie));
+}
+
+TEST_F(RTreeNodeTest, CompareHorizontal) {
+ // One rect with lower x than another should always sort lower than higher x.
+ RTreeRecord low(Rect(1, 0, 10, 10), 1);
+ RTreeRecord middle(Rect(5, 0, 10, 10), 5);
+ EXPECT_TRUE(NodeCompareHorizontal(&low, &middle));
+ EXPECT_FALSE(NodeCompareHorizontal(&middle, &low));
+
+ // Try a non-overlapping higher-x rectangle.
+ RTreeRecord high(Rect(20, -10, 1, 10), 10);
+ EXPECT_TRUE(NodeCompareHorizontal(&low, &high));
+ EXPECT_FALSE(NodeCompareHorizontal(&high, &low));
+
+ // Ties are broken by lowest bottom x value.
+ RTreeRecord shorter_tie(Rect(1, 10, 2, 100), 2);
+ EXPECT_TRUE(NodeCompareHorizontal(&shorter_tie, &low));
+ EXPECT_FALSE(NodeCompareHorizontal(&low, &shorter_tie));
+}
+
+TEST_F(RTreeNodeTest, CompareCenterDistanceFromParent) {
+ // Create a test node we can add children to, for distance comparisons.
+ scoped_ptr<RTreeNode> parent(new RTreeNode);
+
+ // Add three children, one each with centers at (0, 0), (10, 10), (-9, -9),
+ // around which a bounding box will be centered at (0, 0)
+ scoped_ptr<RTreeRecord> center_zero(new RTreeRecord(Rect(-1, -1, 2, 2), 1));
+ parent->AddChild(center_zero.PassAs<RTreeNodeBase>());
+
+ scoped_ptr<RTreeRecord> center_positive(new RTreeRecord(Rect(9, 9, 2, 2), 2));
+ parent->AddChild(center_positive.PassAs<RTreeNodeBase>());
+
+ scoped_ptr<RTreeRecord> center_negative(
+ new RTreeRecord(Rect(-10, -10, 2, 2), 3));
+ parent->AddChild(center_negative.PassAs<RTreeNodeBase>());
+
+ ValidateNode(parent.get(), 1U, 5U);
+ EXPECT_EQ(Rect(-10, -10, 21, 21), parent->rect());
+
+ EXPECT_TRUE(
+ NodeCompareCenterDistanceFromParent(parent->child(0), parent->child(1)));
+ EXPECT_FALSE(
+ NodeCompareCenterDistanceFromParent(parent->child(1), parent->child(0)));
+ EXPECT_TRUE(
+ NodeCompareCenterDistanceFromParent(parent->child(0), parent->child(2)));
+ EXPECT_FALSE(
+ NodeCompareCenterDistanceFromParent(parent->child(2), parent->child(0)));
+ EXPECT_TRUE(
+ NodeCompareCenterDistanceFromParent(parent->child(2), parent->child(1)));
+ EXPECT_FALSE(
+ NodeCompareCenterDistanceFromParent(parent->child(1), parent->child(2)));
+}
+
+TEST_F(RTreeNodeTest, OverlapIncreaseToAdd) {
+ // Create a test node with three children, for overlap comparisons.
+ scoped_ptr<RTreeNode> parent(new RTreeNode);
+
+ // Add three children, each 4 wide and tall, at (0, 0), (3, 3), (6, 6) with
+ // overlapping corners.
+ Rect top(0, 0, 4, 4);
+ parent->AddChild(scoped_ptr<RTreeNodeBase>(new RTreeRecord(top, 1)));
+ Rect middle(3, 3, 4, 4);
+ parent->AddChild(scoped_ptr<RTreeNodeBase>(new RTreeRecord(middle, 2)));
+ Rect bottom(6, 6, 4, 4);
+ parent->AddChild(scoped_ptr<RTreeNodeBase>(new RTreeRecord(bottom, 3)));
+ ValidateNode(parent.get(), 1U, 5U);
+
+ // Test a rect in corner.
+ Rect corner(0, 0, 1, 1);
+ Rect expanded = top;
+ expanded.Union(corner);
+ // It should not add any overlap to add this to the first child at (0, 0).
+ EXPECT_EQ(0, NodeOverlapIncreaseToAdd(
+ parent.get(), corner, parent->child(0), expanded));
+
+ expanded = middle;
+ expanded.Union(corner);
+ // Overlap for middle rectangle should increase from 2 pixels at (3, 3) and
+ // (6, 6) to 17 pixels, as it will now cover 4x4 rectangle top,
+ // so a change of +15.
+ EXPECT_EQ(15, NodeOverlapIncreaseToAdd(
+ parent.get(), corner, parent->child(1), expanded));
+
+ expanded = bottom;
+ expanded.Union(corner);
+ // Overlap for bottom rectangle should increase from 1 pixel at (6, 6) to
+ // 32 pixels, as it will now cover both 4x4 rectangles top and middle,
+ // so a change of 31.
+ EXPECT_EQ(31, NodeOverlapIncreaseToAdd(
+ parent.get(), corner, parent->child(2), expanded));
+
+ // Test a rect that doesn't overlap with anything, in the far right corner.
+ Rect far_corner(9, 0, 1, 1);
+ expanded = top;
+ expanded.Union(far_corner);
+ // Overlap of top should go from 1 to 4, as it will now cover the entire first
+ // row of pixels in middle.
+ EXPECT_EQ(3, NodeOverlapIncreaseToAdd(
+ parent.get(), far_corner, parent->child(0), expanded));
+
+ expanded = middle;
+ expanded.Union(far_corner);
+ // Overlap of middle should go from 2 to 8, as it will cover the rightmost 4
+ // pixels of top and the top 4 pixels of bottom as it expands.
+ EXPECT_EQ(6, NodeOverlapIncreaseToAdd(
+ parent.get(), far_corner, parent->child(1), expanded));
+
+ expanded = bottom;
+ expanded.Union(far_corner);
+ // Overlap of bottom should go from 1 to 4, as it will now cover the rightmost
+ // 4 pixels of middle.
+ EXPECT_EQ(3, NodeOverlapIncreaseToAdd(
+ parent.get(), far_corner, parent->child(2), expanded));
+}
+
+TEST_F(RTreeNodeTest, BuildLowBounds) {
+ RTreeNodes records;
+ records.reserve(10);
+ for (int i = 1; i <= 10; ++i)
+ records.push_back(new RTreeRecord(Rect(0, 0, i, i), i));
+
+ RTreeRects vertical_bounds;
+ RTreeRects horizontal_bounds;
+ NodeBuildLowBounds(
+ records.get(), records.get(), &vertical_bounds, &horizontal_bounds);
+ for (int i = 0; i < 10; ++i) {
+ EXPECT_EQ(records[i]->rect(), vertical_bounds[i]);
+ EXPECT_EQ(records[i]->rect(), horizontal_bounds[i]);
+ }
+}
+
+TEST_F(RTreeNodeTest, BuildHighBounds) {
+ RTreeNodes records;
+ records.reserve(25);
+ for (int i = 0; i < 25; ++i)
+ records.push_back(new RTreeRecord(Rect(i, i, 25 - i, 25 - i), i));
+
+ RTreeRects vertical_bounds;
+ RTreeRects horizontal_bounds;
+ NodeBuildHighBounds(
+ records.get(), records.get(), &vertical_bounds, &horizontal_bounds);
+ for (int i = 0; i < 25; ++i) {
+ EXPECT_EQ(records[i]->rect(), vertical_bounds[i]);
+ EXPECT_EQ(records[i]->rect(), horizontal_bounds[i]);
+ }
+}
+
+TEST_F(RTreeNodeTest, ChooseSplitAxisAndIndexVertical) {
+ RTreeRects low_vertical_bounds;
+ RTreeRects high_vertical_bounds;
+ RTreeRects low_horizontal_bounds;
+ RTreeRects high_horizontal_bounds;
+ // In this test scenario we describe a mirrored, stacked configuration of
+ // horizontal, 1 pixel high rectangles labeled a-f like this:
+ //
+ // shape: | v sort: | h sort: |
+ // -------+---------+---------+
+ // aaaaa | 0 | 0 |
+ // bbb | 1 | 2 |
+ // c | 2 | 4 |
+ // d | 3 | 5 |
+ // eee | 4 | 3 |
+ // fffff | 5 | 1 |
+ //
+ // These are already sorted vertically from top to bottom. Bounding rectangles
+ // of these vertically sorted will be 5 wide, i tall bounding boxes.
+ for (int i = 0; i < 6; ++i) {
+ low_vertical_bounds.push_back(Rect(0, 0, 5, i + 1));
+ high_vertical_bounds.push_back(Rect(0, i, 5, 6 - i));
+ }
+
+ // Low bounds of horizontal sort start with bounds of box a and then jump to
+ // cover everything, as box f is second in horizontal sort.
+ low_horizontal_bounds.push_back(Rect(0, 0, 5, 1));
+ for (int i = 0; i < 5; ++i)
+ low_horizontal_bounds.push_back(Rect(0, 0, 5, 6));
+
+ // High horizontal bounds are hand-calculated.
+ high_horizontal_bounds.push_back(Rect(0, 0, 5, 6));
+ high_horizontal_bounds.push_back(Rect(0, 1, 5, 5));
+ high_horizontal_bounds.push_back(Rect(1, 1, 3, 4));
+ high_horizontal_bounds.push_back(Rect(1, 2, 3, 3));
+ high_horizontal_bounds.push_back(Rect(2, 2, 1, 2));
+ high_horizontal_bounds.push_back(Rect(2, 3, 1, 1));
+
+ int smallest_vertical_margin =
+ NodeSmallestMarginSum(2, 3, low_vertical_bounds, high_vertical_bounds);
+ int smallest_horizontal_margin = NodeSmallestMarginSum(
+ 2, 3, low_horizontal_bounds, high_horizontal_bounds);
+ EXPECT_LT(smallest_vertical_margin, smallest_horizontal_margin);
+
+ EXPECT_EQ(
+ 3U,
+ NodeChooseSplitIndex(2, 5, low_vertical_bounds, high_vertical_bounds));
+}
+
+TEST_F(RTreeNodeTest, ChooseSplitAxisAndIndexHorizontal) {
+ RTreeRects low_vertical_bounds;
+ RTreeRects high_vertical_bounds;
+ RTreeRects low_horizontal_bounds;
+ RTreeRects high_horizontal_bounds;
+ // We rotate the shape from ChooseSplitAxisAndIndexVertical to test
+ // horizontal split axis detection:
+ //
+ // +--------+
+ // | a f |
+ // | ab ef |
+ // sort: | abcdef |
+ // | ab ef |
+ // | a f |
+ // |--------+
+ // v sort: | 024531 |
+ // h sort: | 012345 |
+ // +--------+
+ //
+ // Low bounds of vertical sort start with bounds of box a and then jump to
+ // cover everything, as box f is second in vertical sort.
+ low_vertical_bounds.push_back(Rect(0, 0, 1, 5));
+ for (int i = 0; i < 5; ++i)
+ low_vertical_bounds.push_back(Rect(0, 0, 6, 5));
+
+ // High vertical bounds are hand-calculated.
+ high_vertical_bounds.push_back(Rect(0, 0, 6, 5));
+ high_vertical_bounds.push_back(Rect(1, 0, 5, 5));
+ high_vertical_bounds.push_back(Rect(1, 1, 4, 3));
+ high_vertical_bounds.push_back(Rect(2, 1, 3, 3));
+ high_vertical_bounds.push_back(Rect(2, 2, 2, 1));
+ high_vertical_bounds.push_back(Rect(3, 2, 1, 1));
+
+ // These are already sorted horizontally from left to right. Bounding
+ // rectangles of these horizontally sorted will be i wide, 5 tall bounding
+ // boxes.
+ for (int i = 0; i < 6; ++i) {
+ low_horizontal_bounds.push_back(Rect(0, 0, i + 1, 5));
+ high_horizontal_bounds.push_back(Rect(i, 0, 6 - i, 5));
+ }
+
+ int smallest_vertical_margin =
+ NodeSmallestMarginSum(2, 3, low_vertical_bounds, high_vertical_bounds);
+ int smallest_horizontal_margin = NodeSmallestMarginSum(
+ 2, 3, low_horizontal_bounds, high_horizontal_bounds);
+
+ EXPECT_GT(smallest_vertical_margin, smallest_horizontal_margin);
+
+ EXPECT_EQ(3U,
+ NodeChooseSplitIndex(
+ 2, 5, low_horizontal_bounds, high_horizontal_bounds));
+}
+
+TEST_F(RTreeNodeTest, DivideChildren) {
+ // Create a test node to split.
+ scoped_ptr<RTreeNode> test_node(new RTreeNode);
+ std::vector<RTreeNodeBase*> sorted_children;
+ RTreeRects low_bounds;
+ RTreeRects high_bounds;
+ // Insert 10 record nodes, also inserting them into our children array.
+ for (int i = 1; i <= 10; ++i) {
+ scoped_ptr<RTreeRecord> record(new RTreeRecord(Rect(0, 0, i, i), i));
+ sorted_children.push_back(record.get());
+ test_node->AddChild(record.PassAs<RTreeNodeBase>());
+ low_bounds.push_back(Rect(0, 0, i, i));
+ high_bounds.push_back(Rect(0, 0, 10, 10));
+ }
+ // Split the children in half.
+ scoped_ptr<RTreeNodeBase> split_node_base(NodeDivideChildren(
+ test_node.get(), low_bounds, high_bounds, sorted_children, 5));
+ RTreeNode* split_node = static_cast<RTreeNode*>(split_node_base.get());
+ // Both nodes should be valid.
+ ValidateNode(test_node.get(), 1U, 10U);
+ ValidateNode(split_node, 1U, 10U);
+ // Both nodes should have five children.
+ EXPECT_EQ(5U, test_node->count());
+ EXPECT_EQ(5U, split_node->count());
+ // Test node should have children 1-5, split node should have children 6-10.
+ for (int i = 0; i < 5; ++i) {
+ EXPECT_EQ(i + 1, record(test_node.get(), i)->key());
+ EXPECT_EQ(i + 6, record(split_node, i)->key());
+ }
+}
+
+TEST_F(RTreeNodeTest, RemoveChildNoOrphans) {
+ scoped_ptr<RTreeNode> test_parent(new RTreeNode);
+ test_parent->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 1, 1), 1)));
+ test_parent->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 2, 2), 2)));
+ test_parent->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 3, 3), 3)));
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ RTreeNodes orphans;
+
+ // Remove the middle node.
+ scoped_ptr<RTreeNodeBase> middle_child(
+ test_parent->RemoveChild(test_parent->child(1), &orphans));
+ EXPECT_EQ(0U, orphans.size());
+ EXPECT_EQ(2U, test_parent->count());
+ NodeRecomputeLocalBounds(test_parent.get());
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ // Remove the end node.
+ scoped_ptr<RTreeNodeBase> end_child(
+ test_parent->RemoveChild(test_parent->child(1), &orphans));
+ EXPECT_EQ(0U, orphans.size());
+ EXPECT_EQ(1U, test_parent->count());
+ NodeRecomputeLocalBounds(test_parent.get());
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ // Remove the first node.
+ scoped_ptr<RTreeNodeBase> first_child(
+ test_parent->RemoveChild(test_parent->child(0), &orphans));
+ EXPECT_EQ(0U, orphans.size());
+ EXPECT_EQ(0U, test_parent->count());
+}
+
+TEST_F(RTreeNodeTest, RemoveChildOrphans) {
+ // Build binary tree of Nodes of height 4, keeping weak pointers to the
+ // Levels 0 and 1 Nodes and the Records so we can test removal of them below.
+ std::vector<RTreeNode*> level_1_children;
+ std::vector<RTreeNode*> level_0_children;
+ std::vector<RTreeRecord*> records;
+ int id = 1;
+ scoped_ptr<RTreeNode> root(NewNodeAtLevel(2));
+ for (int i = 0; i < 2; ++i) {
+ scoped_ptr<RTreeNode> level_1_child(NewNodeAtLevel(1));
+ for (int j = 0; j < 2; ++j) {
+ scoped_ptr<RTreeNode> level_0_child(new RTreeNode);
+ for (int k = 0; k < 2; ++k) {
+ scoped_ptr<RTreeRecord> record(
+ new RTreeRecord(Rect(0, 0, id, id), id));
+ ++id;
+ records.push_back(record.get());
+ level_0_child->AddChild(record.PassAs<RTreeNodeBase>());
+ }
+ level_0_children.push_back(level_0_child.get());
+ level_1_child->AddChild(level_0_child.PassAs<RTreeNodeBase>());
+ }
+ level_1_children.push_back(level_1_child.get());
+ root->AddChild(level_1_child.PassAs<RTreeNodeBase>());
+ }
+
+ // This should now be a valid tree structure.
+ ValidateNode(root.get(), 2U, 2U);
+ EXPECT_EQ(2U, level_1_children.size());
+ EXPECT_EQ(4U, level_0_children.size());
+ EXPECT_EQ(8U, records.size());
+
+ // Now remove all of the level 0 nodes so we get the record nodes as orphans.
+ RTreeNodes orphans;
+ for (size_t i = 0; i < level_0_children.size(); ++i)
+ level_1_children[i / 2]->RemoveChild(level_0_children[i], &orphans);
+
+ // Orphans should be all 8 records but no order guarantee.
+ EXPECT_EQ(8U, orphans.size());
+ for (std::vector<RTreeRecord*>::iterator it = records.begin();
+ it != records.end(); ++it) {
+ RTreeNodes::iterator orphan =
+ std::find(orphans.begin(), orphans.end(), *it);
+ EXPECT_NE(orphan, orphans.end());
+ orphans.erase(orphan);
+ }
+ EXPECT_EQ(0U, orphans.size());
+}
+
+TEST_F(RTreeNodeTest, RemoveAndReturnLastChild) {
+ scoped_ptr<RTreeNode> test_parent(new RTreeNode);
+ test_parent->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 1, 1), 1)));
+ test_parent->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 2, 2), 2)));
+ test_parent->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 0, 3, 3), 3)));
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ RTreeNodeBase* child = test_parent->child(2);
+ scoped_ptr<RTreeNodeBase> last_child(test_parent->RemoveAndReturnLastChild());
+ EXPECT_EQ(child, last_child.get());
+ EXPECT_EQ(2U, test_parent->count());
+ NodeRecomputeLocalBounds(test_parent.get());
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ child = test_parent->child(1);
+ scoped_ptr<RTreeNodeBase> middle_child(
+ test_parent->RemoveAndReturnLastChild());
+ EXPECT_EQ(child, middle_child.get());
+ EXPECT_EQ(1U, test_parent->count());
+ NodeRecomputeLocalBounds(test_parent.get());
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ child = test_parent->child(0);
+ scoped_ptr<RTreeNodeBase> first_child(
+ test_parent->RemoveAndReturnLastChild());
+ EXPECT_EQ(child, first_child.get());
+ EXPECT_EQ(0U, test_parent->count());
+}
+
+TEST_F(RTreeNodeTest, LeastOverlapIncrease) {
+ scoped_ptr<RTreeNode> test_parent(NewNodeAtLevel(1));
+ // Construct 4 nodes with 1x2 rects spaced horizontally 1 pixel apart, or:
+ //
+ // a b c d
+ // a b c d
+ //
+ for (int i = 0; i < 4; ++i) {
+ scoped_ptr<RTreeNode> node(new RTreeNode);
+ scoped_ptr<RTreeRecord> record(
+ new RTreeRecord(Rect(i * 2, 0, 1, 2), i + 1));
+ node->AddChild(record.PassAs<RTreeNodeBase>());
+ test_parent->AddChild(node.PassAs<RTreeNodeBase>());
+ }
+
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ // Test rect at (7, 0) should require minimum overlap on the part of the
+ // fourth rectangle to add:
+ //
+ // a b c dT
+ // a b c d
+ //
+ Rect test_rect_far(7, 0, 1, 1);
+ RTreeRects expanded_rects;
+ BuildExpandedRects(test_parent.get(), test_rect_far, &expanded_rects);
+ RTreeNode* result = NodeLeastOverlapIncrease(
+ test_parent.get(), test_rect_far, expanded_rects);
+ EXPECT_EQ(4, record(result, 0)->key());
+
+ // Test rect covering the bottom half of all children should be a 4-way tie,
+ // so LeastOverlapIncrease should return NULL:
+ //
+ // a b c d
+ // TTTTTTT
+ //
+ Rect test_rect_tie(0, 1, 7, 1);
+ BuildExpandedRects(test_parent.get(), test_rect_tie, &expanded_rects);
+ result = NodeLeastOverlapIncrease(
+ test_parent.get(), test_rect_tie, expanded_rects);
+ EXPECT_TRUE(result == NULL);
+
+ // Test rect completely inside c should return the third rectangle:
+ //
+ // a b T d
+ // a b c d
+ //
+ Rect test_rect_inside(4, 0, 1, 1);
+ BuildExpandedRects(test_parent.get(), test_rect_inside, &expanded_rects);
+ result = NodeLeastOverlapIncrease(
+ test_parent.get(), test_rect_inside, expanded_rects);
+ EXPECT_EQ(3, record(result, 0)->key());
+
+ // Add a rectangle that overlaps completely with rectangle c, to test
+ // when there is a tie between two completely contained rectangles:
+ //
+ // a b Ted
+ // a b eed
+ //
+ scoped_ptr<RTreeNode> record_parent(new RTreeNode);
+ record_parent->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(4, 0, 2, 2), 9)));
+ test_parent->AddChild(record_parent.PassAs<RTreeNodeBase>());
+ BuildExpandedRects(test_parent.get(), test_rect_inside, &expanded_rects);
+ result = NodeLeastOverlapIncrease(
+ test_parent.get(), test_rect_inside, expanded_rects);
+ EXPECT_TRUE(result == NULL);
+}
+
+TEST_F(RTreeNodeTest, LeastAreaEnlargement) {
+ scoped_ptr<RTreeNode> test_parent(NewNodeAtLevel(1));
+ // Construct 4 nodes in a cross-hairs style configuration:
+ //
+ // a
+ // b c
+ // d
+ //
+ scoped_ptr<RTreeNode> node(new RTreeNode);
+ node->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(1, 0, 1, 1), 1)));
+ test_parent->AddChild(node.PassAs<RTreeNodeBase>());
+ node.reset(new RTreeNode);
+ node->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 1, 1, 1), 2)));
+ test_parent->AddChild(node.PassAs<RTreeNodeBase>());
+ node.reset(new RTreeNode);
+ node->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(2, 1, 1, 1), 3)));
+ test_parent->AddChild(node.PassAs<RTreeNodeBase>());
+ node.reset(new RTreeNode);
+ node->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(1, 2, 1, 1), 4)));
+ test_parent->AddChild(node.PassAs<RTreeNodeBase>());
+
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ // Test rect at (1, 3) should require minimum area to add to Node d:
+ //
+ // a
+ // b c
+ // d
+ // T
+ //
+ Rect test_rect_below(1, 3, 1, 1);
+ RTreeRects expanded_rects;
+ BuildExpandedRects(test_parent.get(), test_rect_below, &expanded_rects);
+ RTreeNode* result = NodeLeastAreaEnlargement(
+ test_parent.get(), test_rect_below, expanded_rects);
+ EXPECT_EQ(4, record(result, 0)->key());
+
+ // Test rect completely inside b should require minimum area to add to Node b:
+ //
+ // a
+ // T c
+ // d
+ //
+ Rect test_rect_inside(0, 1, 1, 1);
+ BuildExpandedRects(test_parent.get(), test_rect_inside, &expanded_rects);
+ result = NodeLeastAreaEnlargement(
+ test_parent.get(), test_rect_inside, expanded_rects);
+ EXPECT_EQ(2, record(result, 0)->key());
+
+ // Add e at (0, 1) to overlap b and c, to test tie-breaking:
+ //
+ // a
+ // eee
+ // d
+ //
+ node.reset(new RTreeNode);
+ node->AddChild(
+ scoped_ptr<RTreeNodeBase>(new RTreeRecord(Rect(0, 1, 3, 1), 7)));
+ test_parent->AddChild(node.PassAs<RTreeNodeBase>());
+
+ ValidateNode(test_parent.get(), 1U, 5U);
+
+ // Test rect at (3, 1) should tie between c and e, but c has smaller area so
+ // the algorithm should select c:
+ //
+ //
+ // a
+ // eeeT
+ // d
+ //
+ Rect test_rect_tie_breaker(3, 1, 1, 1);
+ BuildExpandedRects(test_parent.get(), test_rect_tie_breaker, &expanded_rects);
+ result = NodeLeastAreaEnlargement(
+ test_parent.get(), test_rect_tie_breaker, expanded_rects);
+ EXPECT_EQ(3, record(result, 0)->key());
+}
+
+// RTreeTest ------------------------------------------------------------------
+
+// An empty RTree should never return AppendIntersectingRecords results, and
+// RTrees should be empty upon construction.
+TEST_F(RTreeTest, AppendIntersectingRecordsOnEmptyTree) {
+ RT rt(2, 10);
+ ValidateRTree(&rt);
+ RT::Matches results;
+ Rect test_rect(25, 25);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(0U, results.size());
+ ValidateRTree(&rt);
+}
+
+// Clear should empty the tree, meaning that all queries should not return
+// results after.
+TEST_F(RTreeTest, ClearEmptiesTreeOfSingleNode) {
+ RT rt(2, 5);
+ rt.Insert(Rect(0, 0, 100, 100), 1);
+ rt.Clear();
+ RT::Matches results;
+ Rect test_rect(1, 1);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(0U, results.size());
+ ValidateRTree(&rt);
+}
+
+// Even with a complex internal structure, clear should empty the tree, meaning
+// that all queries should not return results after.
+TEST_F(RTreeTest, ClearEmptiesTreeOfManyNodes) {
+ RT rt(2, 5);
+ AddStackedSquares(&rt, 100);
+ rt.Clear();
+ RT::Matches results;
+ Rect test_rect(1, 1);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(0U, results.size());
+ ValidateRTree(&rt);
+}
+
+// Duplicate inserts should overwrite previous inserts.
+TEST_F(RTreeTest, DuplicateInsertsOverwrite) {
+ RT rt(2, 5);
+ // Add 100 stacked squares, but always with duplicate key of 0.
+ for (int i = 1; i <= 100; ++i) {
+ rt.Insert(Rect(0, 0, i, i), 0);
+ ValidateRTree(&rt);
+ }
+ RT::Matches results;
+ Rect test_rect(1, 1);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(1U, results.size());
+ EXPECT_EQ(1U, results.count(0));
+}
+
+// Call Remove() once on something that's been inserted repeatedly.
+TEST_F(RTreeTest, DuplicateInsertRemove) {
+ RT rt(3, 9);
+ AddStackedSquares(&rt, 25);
+ for (int i = 1; i <= 100; ++i) {
+ rt.Insert(Rect(0, 0, i, i), 26);
+ ValidateRTree(&rt);
+ }
+ rt.Remove(26);
+ RT::Matches results;
+ Rect test_rect(1, 1);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(25U, results.size());
+ VerifyAllKeys(results);
+}
+
+// Call Remove() repeatedly on something that's been inserted once.
+TEST_F(RTreeTest, InsertDuplicateRemove) {
+ RT rt(7, 15);
+ AddStackedSquares(&rt, 101);
+ for (int i = 0; i < 100; ++i) {
+ rt.Remove(101);
+ ValidateRTree(&rt);
+ }
+ RT::Matches results;
+ Rect test_rect(1, 1);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(100U, results.size());
+ VerifyAllKeys(results);
+}
+
+// Stacked rects should meet all matching queries regardless of nesting.
+TEST_F(RTreeTest, AppendIntersectingRecordsStackedSquaresNestedHit) {
+ RT rt(2, 5);
+ AddStackedSquares(&rt, 100);
+ RT::Matches results;
+ Rect test_rect(1, 1);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(100U, results.size());
+ VerifyAllKeys(results);
+}
+
+// Stacked rects should meet all matching queries when contained completely by
+// the query rectangle.
+TEST_F(RTreeTest, AppendIntersectingRecordsStackedSquaresContainedHit) {
+ RT rt(2, 10);
+ AddStackedSquares(&rt, 100);
+ RT::Matches results;
+ Rect test_rect(0, 0, 100, 100);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(100U, results.size());
+ VerifyAllKeys(results);
+}
+
+// Stacked rects should miss a missing query when the query has no intersection
+// with the rects.
+TEST_F(RTreeTest, AppendIntersectingRecordsStackedSquaresCompleteMiss) {
+ RT rt(2, 7);
+ AddStackedSquares(&rt, 100);
+ RT::Matches results;
+ Rect test_rect(150, 150, 100, 100);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(0U, results.size());
+}
+
+// Removing half the nodes after insertion should still result in a valid tree.
+TEST_F(RTreeTest, RemoveHalfStackedRects) {
+ RT rt(2, 11);
+ AddStackedSquares(&rt, 200);
+ for (int i = 101; i <= 200; ++i) {
+ rt.Remove(i);
+ ValidateRTree(&rt);
+ }
+ RT::Matches results;
+ Rect test_rect(1, 1);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(100U, results.size());
+ VerifyAllKeys(results);
+
+ // Add the nodes back in.
+ for (int i = 101; i <= 200; ++i) {
+ rt.Insert(Rect(0, 0, i, i), i);
+ ValidateRTree(&rt);
+ }
+ results.clear();
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(200U, results.size());
+ VerifyAllKeys(results);
+}
+
+TEST_F(RTreeTest, InsertDupToRoot) {
+ RT rt(2, 5);
+ rt.Insert(Rect(0, 0, 1, 2), 1);
+ ValidateRTree(&rt);
+ rt.Insert(Rect(0, 0, 2, 1), 1);
+ ValidateRTree(&rt);
+}
+
+TEST_F(RTreeTest, InsertNegativeCoordsRect) {
+ RT rt(5, 11);
+ for (int i = 1; i <= 100; ++i) {
+ rt.Insert(Rect(-i, -i, i, i), (i * 2) - 1);
+ ValidateRTree(&rt);
+ rt.Insert(Rect(0, 0, i, i), i * 2);
+ ValidateRTree(&rt);
+ }
+ RT::Matches results;
+ Rect test_rect(-1, -1, 2, 2);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(200U, results.size());
+ VerifyAllKeys(results);
+}
+
+TEST_F(RTreeTest, RemoveNegativeCoordsRect) {
+ RT rt(7, 21);
+
+ // Add 100 positive stacked squares.
+ AddStackedSquares(&rt, 100);
+
+ // Now add 100 negative stacked squares.
+ for (int i = 101; i <= 200; ++i) {
+ rt.Insert(Rect(100 - i, 100 - i, i - 100, i - 100), 301 - i);
+ ValidateRTree(&rt);
+ }
+
+ // Now remove half of the negative squares.
+ for (int i = 101; i <= 150; ++i) {
+ rt.Remove(301 - i);
+ ValidateRTree(&rt);
+ }
+
+ // Queries should return 100 positive and 50 negative stacked squares.
+ RT::Matches results;
+ Rect test_rect(-1, -1, 2, 2);
+ rt.AppendIntersectingRecords(test_rect, &results);
+ EXPECT_EQ(150U, results.size());
+ VerifyAllKeys(results);
+}
+
+TEST_F(RTreeTest, InsertEmptyRectReplacementRemovesKey) {
+ RT rt(10, 31);
+ AddStackedSquares(&rt, 50);
+ ValidateRTree(&rt);
+
+ // Replace last square with empty rect.
+ rt.Insert(Rect(), 50);
+ ValidateRTree(&rt);
+
+ // Now query large area to get all rects in tree.
+ RT::Matches results;
+ Rect test_rect(0, 0, 100, 100);
+ rt.AppendIntersectingRecords(test_rect, &results);
+
+ // Should only be 49 rects in tree.
+ EXPECT_EQ(49U, results.size());
+ VerifyAllKeys(results);
+}
+
+TEST_F(RTreeTest, InsertReplacementMaintainsTree) {
+ RT rt(2, 5);
+ AddStackedSquares(&rt, 100);
+ ValidateRTree(&rt);
+
+ for (int i = 1; i <= 100; ++i) {
+ rt.Insert(Rect(0, 0, 0, 0), i);
+ ValidateRTree(&rt);
+ }
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/rect.cc b/chromium/ui/gfx/geometry/rect.cc
index 8372cc4e7c5..f418e175b89 100644
--- a/chromium/ui/gfx/rect.cc
+++ b/chromium/ui/gfx/geometry/rect.cc
@@ -2,20 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/rect.h"
+#include "ui/gfx/geometry/rect.h"
#include <algorithm>
#if defined(OS_WIN)
#include <windows.h>
-#elif defined(TOOLKIT_GTK)
-#include <gdk/gdk.h>
#endif
#include "base/logging.h"
#include "base/strings/stringprintf.h"
-#include "ui/gfx/insets.h"
-#include "ui/gfx/rect_base_impl.h"
+#include "ui/gfx/geometry/insets.h"
+#include "ui/gfx/geometry/rect_base_impl.h"
namespace gfx {
@@ -35,12 +33,6 @@ Rect::Rect(const CGRect& r)
set_width(r.size.width);
set_height(r.size.height);
}
-#elif defined(TOOLKIT_GTK)
-Rect::Rect(const GdkRectangle& r)
- : RectBaseT(gfx::Point(r.x, r.y)) {
- set_width(r.width);
- set_height(r.height);
-}
#endif
#if defined(OS_WIN)
@@ -56,11 +48,6 @@ RECT Rect::ToRECT() const {
CGRect Rect::ToCGRect() const {
return CGRectMake(x(), y(), width(), height());
}
-#elif defined(TOOLKIT_GTK)
-GdkRectangle Rect::ToGdkRectangle() const {
- GdkRectangle r = {x(), y(), width(), height()};
- return r;
-}
#endif
std::string Rect::ToString() const {
diff --git a/chromium/ui/gfx/geometry/rect.h b/chromium/ui/gfx/geometry/rect.h
new file mode 100644
index 00000000000..28d37bc31b3
--- /dev/null
+++ b/chromium/ui/gfx/geometry/rect.h
@@ -0,0 +1,139 @@
+// 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.
+
+// Defines a simple integer 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_H_
+#define UI_GFX_GEOMETRY_RECT_H_
+
+#include <cmath>
+#include <string>
+
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/rect_base.h"
+#include "ui/gfx/geometry/rect_f.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/vector2d.h"
+
+#if defined(OS_WIN)
+typedef struct tagRECT RECT;
+#elif defined(OS_IOS)
+#include <CoreGraphics/CoreGraphics.h>
+#elif defined(OS_MACOSX)
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+namespace gfx {
+
+class Insets;
+
+class GFX_EXPORT Rect
+ : public RectBase<Rect, Point, Size, Insets, Vector2d, int> {
+ public:
+ Rect() : RectBase<Rect, Point, Size, Insets, Vector2d, int>(Point()) {}
+
+ Rect(int width, int height)
+ : RectBase<Rect, Point, Size, Insets, Vector2d, int>
+ (Size(width, height)) {}
+
+ Rect(int x, int y, int width, int height)
+ : RectBase<Rect, Point, Size, Insets, Vector2d, int>
+ (Point(x, y), Size(width, height)) {}
+
+#if defined(OS_WIN)
+ explicit Rect(const RECT& r);
+#elif defined(OS_MACOSX)
+ explicit Rect(const CGRect& r);
+#endif
+
+ explicit Rect(const gfx::Size& size)
+ : RectBase<Rect, Point, Size, Insets, Vector2d, int>(size) {}
+
+ Rect(const gfx::Point& origin, const gfx::Size& size)
+ : RectBase<Rect, Point, Size, Insets, Vector2d, int>(origin, size) {}
+
+ ~Rect() {}
+
+#if defined(OS_WIN)
+ // Construct an equivalent Win32 RECT object.
+ RECT ToRECT() const;
+#elif defined(OS_MACOSX)
+ // Construct an equivalent CoreGraphics object.
+ CGRect ToCGRect() const;
+#endif
+
+ operator RectF() const {
+ return RectF(origin().x(), origin().y(), size().width(), size().height());
+ }
+
+ std::string ToString() const;
+};
+
+inline bool operator==(const Rect& lhs, const Rect& rhs) {
+ return lhs.origin() == rhs.origin() && lhs.size() == rhs.size();
+}
+
+inline bool operator!=(const Rect& lhs, const Rect& rhs) {
+ return !(lhs == rhs);
+}
+
+GFX_EXPORT Rect operator+(const Rect& lhs, const Vector2d& rhs);
+GFX_EXPORT Rect operator-(const Rect& lhs, const Vector2d& rhs);
+
+inline Rect operator+(const Vector2d& lhs, const Rect& rhs) {
+ return rhs + lhs;
+}
+
+GFX_EXPORT Rect IntersectRects(const Rect& a, const Rect& b);
+GFX_EXPORT Rect UnionRects(const Rect& a, const Rect& b);
+GFX_EXPORT Rect SubtractRects(const Rect& a, const Rect& b);
+
+// Constructs a rectangle with |p1| and |p2| as opposite corners.
+//
+// This could also be thought of as "the smallest rect that contains both
+// 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.
+GFX_EXPORT Rect BoundingRect(const Point& p1, const Point& p2);
+
+inline Rect ScaleToEnclosingRect(const Rect& rect,
+ float x_scale,
+ float y_scale) {
+ int x = std::floor(rect.x() * x_scale);
+ int y = std::floor(rect.y() * y_scale);
+ int r = rect.width() == 0 ? x : std::ceil(rect.right() * x_scale);
+ int b = rect.height() == 0 ? y : std::ceil(rect.bottom() * y_scale);
+ return Rect(x, y, r - x, b - y);
+}
+
+inline Rect ScaleToEnclosingRect(const Rect& rect, float scale) {
+ return ScaleToEnclosingRect(rect, scale, scale);
+}
+
+inline Rect ScaleToEnclosedRect(const Rect& rect,
+ float x_scale,
+ float y_scale) {
+ int x = std::ceil(rect.x() * x_scale);
+ int y = std::ceil(rect.y() * y_scale);
+ int r = rect.width() == 0 ? x : std::floor(rect.right() * x_scale);
+ int b = rect.height() == 0 ? y : std::floor(rect.bottom() * y_scale);
+ return Rect(x, y, r - x, b - y);
+}
+
+inline Rect ScaleToEnclosedRect(const Rect& rect, float scale) {
+ return ScaleToEnclosedRect(rect, scale, scale);
+}
+
+#if !defined(COMPILER_MSVC)
+extern template class RectBase<Rect, Point, Size, Insets, Vector2d, int>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_RECT_H_
diff --git a/chromium/ui/gfx/rect_base.h b/chromium/ui/gfx/geometry/rect_base.h
index 412836ced19..b0a9b06a6b5 100644
--- a/chromium/ui/gfx/rect_base.h
+++ b/chromium/ui/gfx/geometry/rect_base.h
@@ -9,8 +9,8 @@
// 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_RECT_BASE_H_
-#define UI_GFX_RECT_BASE_H_
+#ifndef UI_GFX_GEOMETRY_RECT_BASE_H_
+#define UI_GFX_GEOMETRY_RECT_BASE_H_
#include <string>
@@ -171,4 +171,4 @@ class GFX_EXPORT RectBase {
} // namespace gfx
-#endif // UI_GFX_RECT_BASE_H_
+#endif // UI_GFX_GEOMETRY_RECT_BASE_H_
diff --git a/chromium/ui/gfx/rect_base_impl.h b/chromium/ui/gfx/geometry/rect_base_impl.h
index 52201691a1b..7720608e9b5 100644
--- a/chromium/ui/gfx/rect_base_impl.h
+++ b/chromium/ui/gfx/geometry/rect_base_impl.h
@@ -4,10 +4,9 @@
#include <limits>
-#include "ui/gfx/rect_base.h"
-
#include "base/logging.h"
#include "base/strings/stringprintf.h"
+#include "ui/gfx/geometry/rect_base.h"
// This file provides the implementation for RectBaese template and
// used to instantiate the base class for Rect and RectF classes.
diff --git a/chromium/ui/gfx/rect_conversions.cc b/chromium/ui/gfx/geometry/rect_conversions.cc
index a54a49a23d6..cceeb83a0ae 100644
--- a/chromium/ui/gfx/rect_conversions.cc
+++ b/chromium/ui/gfx/geometry/rect_conversions.cc
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/geometry/rect_conversions.h"
#include <algorithm>
#include <cmath>
#include "base/logging.h"
-#include "ui/gfx/safe_integer_conversions.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
namespace gfx {
diff --git a/chromium/ui/gfx/geometry/rect_conversions.h b/chromium/ui/gfx/geometry/rect_conversions.h
new file mode 100644
index 00000000000..617074abeee
--- /dev/null
+++ b/chromium/ui/gfx/geometry/rect_conversions.h
@@ -0,0 +1,36 @@
+// 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_CONVERSIONS_H_
+#define UI_GFX_GEOMETRY_RECT_CONVERSIONS_H_
+
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace gfx {
+
+// Returns the smallest Rect that encloses the given RectF.
+GFX_EXPORT Rect ToEnclosingRect(const RectF& rect);
+
+// Returns the largest Rect that is enclosed by the given RectF.
+GFX_EXPORT Rect ToEnclosedRect(const RectF& rect);
+
+// Returns the Rect after snapping the corners of the RectF to an integer grid.
+// This should only be used when the RectF you provide is expected to be an
+// integer rect with floating point error. If it is an arbitrary RectF, then
+// you should use a different method.
+GFX_EXPORT Rect ToNearestRect(const RectF& rect);
+
+// Returns true if the Rect produced after snapping the corners of the RectF
+// to an integer grid is withing |distance|.
+GFX_EXPORT bool IsNearestRectWithinDistance(
+ const gfx::RectF& rect, float distance);
+
+// Returns a Rect obtained by flooring the values of the given RectF.
+// Please prefer the previous two functions in new code.
+GFX_EXPORT Rect ToFlooredRectDeprecated(const RectF& rect);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_RECT_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/rect_f.cc b/chromium/ui/gfx/geometry/rect_f.cc
index c55752aa843..44c08aafaff 100644
--- a/chromium/ui/gfx/rect_f.cc
+++ b/chromium/ui/gfx/geometry/rect_f.cc
@@ -2,15 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/rect_f.h"
+#include "ui/gfx/geometry/rect_f.h"
#include <algorithm>
#include "base/logging.h"
#include "base/strings/stringprintf.h"
-#include "ui/gfx/insets_f.h"
-#include "ui/gfx/rect_base_impl.h"
-#include "ui/gfx/safe_integer_conversions.h"
+#include "ui/gfx/geometry/insets_f.h"
+#include "ui/gfx/geometry/rect_base_impl.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
namespace gfx {
diff --git a/chromium/ui/gfx/geometry/rect_f.h b/chromium/ui/gfx/geometry/rect_f.h
new file mode 100644
index 00000000000..50ea76bff9f
--- /dev/null
+++ b/chromium/ui/gfx/geometry/rect_f.h
@@ -0,0 +1,113 @@
+// 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_F_H_
+#define UI_GFX_GEOMETRY_RECT_F_H_
+
+#include <string>
+
+#include "ui/gfx/geometry/point_f.h"
+#include "ui/gfx/geometry/rect_base.h"
+#include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace gfx {
+
+class InsetsF;
+
+// A floating version of gfx::Rect.
+class GFX_EXPORT RectF
+ : public RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float> {
+ public:
+ RectF()
+ : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
+ (SizeF()) {}
+
+ RectF(float width, float height)
+ : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
+ (SizeF(width, height)) {}
+
+ RectF(float x, float y, float width, float height)
+ : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
+ (PointF(x, y), SizeF(width, height)) {}
+
+ explicit RectF(const SizeF& size)
+ : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
+ (size) {}
+
+ RectF(const PointF& origin, const SizeF& size)
+ : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
+ (origin, size) {}
+
+ ~RectF() {}
+
+ // Scales the rectangle by |scale|.
+ void Scale(float scale) {
+ Scale(scale, scale);
+ }
+
+ void Scale(float x_scale, float y_scale) {
+ set_origin(ScalePoint(origin(), x_scale, y_scale));
+ set_size(ScaleSize(size(), 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
+ // clamping.
+ bool IsExpressibleAsRect() const;
+
+ std::string ToString() const;
+};
+
+inline 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) {
+ return !(lhs == rhs);
+}
+
+inline RectF operator+(const RectF& lhs, const Vector2dF& rhs) {
+ return RectF(lhs.x() + rhs.x(), lhs.y() + rhs.y(),
+ lhs.width(), lhs.height());
+}
+
+inline RectF operator-(const RectF& lhs, const Vector2dF& rhs) {
+ return RectF(lhs.x() - rhs.x(), lhs.y() - rhs.y(),
+ lhs.width(), lhs.height());
+}
+
+inline RectF operator+(const Vector2dF& lhs, const RectF& rhs) {
+ return rhs + lhs;
+}
+
+GFX_EXPORT RectF IntersectRects(const RectF& a, const RectF& b);
+GFX_EXPORT RectF UnionRects(const RectF& a, const RectF& b);
+GFX_EXPORT RectF SubtractRects(const RectF& a, const RectF& b);
+
+inline RectF ScaleRect(const RectF& r, float x_scale, float y_scale) {
+ return RectF(r.x() * x_scale, r.y() * y_scale,
+ r.width() * x_scale, r.height() * y_scale);
+}
+
+inline RectF ScaleRect(const RectF& r, float scale) {
+ return ScaleRect(r, scale, scale);
+}
+
+// Constructs a rectangle with |p1| and |p2| as opposite corners.
+//
+// This could also be thought of as "the smallest rect that contains both
+// 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.
+GFX_EXPORT RectF BoundingRect(const PointF& p1, const PointF& p2);
+
+#if !defined(COMPILER_MSVC)
+extern template class RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_RECT_F_H_
diff --git a/chromium/ui/gfx/rect_unittest.cc b/chromium/ui/gfx/geometry/rect_unittest.cc
index 31a156b7910..5fcd76b706b 100644
--- a/chromium/ui/gfx/rect_unittest.cc
+++ b/chromium/ui/gfx/geometry/rect_unittest.cc
@@ -1,14 +1,17 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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 <limits>
+
#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/rect_conversions.h"
-#include "ui/gfx/skia_util.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_conversions.h"
-#include <limits>
+#if defined(OS_WIN)
+#include <windows.h>
+#endif
namespace gfx {
@@ -414,20 +417,6 @@ TEST(RectTest, SharesEdgeWith) {
EXPECT_FALSE(r.SharesEdgeWith(just_right_no_edge));
}
-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());
-}
-
// 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); } }
diff --git a/chromium/ui/gfx/geometry/safe_integer_conversions.h b/chromium/ui/gfx/geometry/safe_integer_conversions.h
new file mode 100644
index 00000000000..4d289ecabaf
--- /dev/null
+++ b/chromium/ui/gfx/geometry/safe_integer_conversions.h
@@ -0,0 +1,54 @@
+// 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_SAFE_INTEGER_CONVERSIONS_H_
+#define UI_GFX_GEOMETRY_SAFE_INTEGER_CONVERSIONS_H_
+
+#include <cmath>
+#include <limits>
+
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+inline int ClampToInt(float value) {
+ if (value != value)
+ return 0; // no int NaN.
+ if (value >= std::numeric_limits<int>::max())
+ return std::numeric_limits<int>::max();
+ if (value <= std::numeric_limits<int>::min())
+ return std::numeric_limits<int>::min();
+ return static_cast<int>(value);
+}
+
+inline int ToFlooredInt(float value) {
+ return ClampToInt(std::floor(value));
+}
+
+inline int ToCeiledInt(float value) {
+ return ClampToInt(std::ceil(value));
+}
+
+inline int ToRoundedInt(float value) {
+ float rounded;
+ if (value >= 0.0f)
+ rounded = std::floor(value + 0.5f);
+ else
+ rounded = std::ceil(value - 0.5f);
+ return ClampToInt(rounded);
+}
+
+inline bool IsExpressibleAsInt(float value) {
+ if (value != value)
+ return false; // no int NaN.
+ if (value > std::numeric_limits<int>::max())
+ return false;
+ if (value < std::numeric_limits<int>::min())
+ return false;
+ return true;
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_SAFE_INTEGER_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/safe_integer_conversions_unittest.cc b/chromium/ui/gfx/geometry/safe_integer_conversions_unittest.cc
index 1268f8bbf32..e00671b264a 100644
--- a/chromium/ui/gfx/safe_integer_conversions_unittest.cc
+++ b/chromium/ui/gfx/geometry/safe_integer_conversions_unittest.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/safe_integer_conversions.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
#include <limits>
diff --git a/chromium/ui/gfx/size.cc b/chromium/ui/gfx/geometry/size.cc
index aa003e8c6df..38ec4b3a516 100644
--- a/chromium/ui/gfx/size.cc
+++ b/chromium/ui/gfx/geometry/size.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/size.h"
+#include "ui/gfx/geometry/size.h"
#if defined(OS_WIN)
#include <windows.h>
diff --git a/chromium/ui/gfx/geometry/size.h b/chromium/ui/gfx/geometry/size.h
new file mode 100644
index 00000000000..78984b073f4
--- /dev/null
+++ b/chromium/ui/gfx/geometry/size.h
@@ -0,0 +1,67 @@
+// 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_H_
+#define UI_GFX_GEOMETRY_SIZE_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "ui/gfx/geometry/size_base.h"
+#include "ui/gfx/geometry/size_f.h"
+#include "ui/gfx/gfx_export.h"
+
+#if defined(OS_WIN)
+typedef struct tagSIZE SIZE;
+#elif defined(OS_IOS)
+#include <CoreGraphics/CoreGraphics.h>
+#elif defined(OS_MACOSX)
+#include <ApplicationServices/ApplicationServices.h>
+#endif
+
+namespace gfx {
+
+// A size has width and height values.
+class GFX_EXPORT Size : public SizeBase<Size, int> {
+ public:
+ Size() : SizeBase<Size, int>(0, 0) {}
+ Size(int width, int height) : SizeBase<Size, int>(width, height) {}
+#if defined(OS_MACOSX)
+ explicit Size(const CGSize& s);
+#endif
+
+ ~Size() {}
+
+#if defined(OS_MACOSX)
+ Size& operator=(const CGSize& s);
+#endif
+
+#if defined(OS_WIN)
+ SIZE ToSIZE() const;
+#elif defined(OS_MACOSX)
+ CGSize ToCGSize() const;
+#endif
+
+ operator SizeF() const {
+ return SizeF(width(), height());
+ }
+
+ std::string ToString() const;
+};
+
+inline bool operator==(const Size& lhs, const Size& rhs) {
+ return lhs.width() == rhs.width() && lhs.height() == rhs.height();
+}
+
+inline bool operator!=(const Size& lhs, const Size& rhs) {
+ return !(lhs == rhs);
+}
+
+#if !defined(COMPILER_MSVC)
+extern template class SizeBase<Size, int>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_SIZE_H_
diff --git a/chromium/ui/gfx/size_base.h b/chromium/ui/gfx/geometry/size_base.h
index c8349dc4b77..88a98ef4584 100644
--- a/chromium/ui/gfx/size_base.h
+++ b/chromium/ui/gfx/geometry/size_base.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef UI_GFX_SIZE_BASE_H_
-#define UI_GFX_SIZE_BASE_H_
+#ifndef UI_GFX_GEOMETRY_SIZE_BASE_H_
+#define UI_GFX_GEOMETRY_SIZE_BASE_H_
#include "ui/gfx/gfx_export.h"
@@ -66,4 +66,4 @@ class GFX_EXPORT SizeBase {
} // namespace gfx
-#endif // UI_GFX_SIZE_BASE_H_
+#endif // UI_GFX_GEOMETRY_SIZE_BASE_H_
diff --git a/chromium/ui/gfx/size_conversions.cc b/chromium/ui/gfx/geometry/size_conversions.cc
index eacbeb4fc8d..c924e86c9ae 100644
--- a/chromium/ui/gfx/size_conversions.cc
+++ b/chromium/ui/gfx/geometry/size_conversions.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/size_conversions.h"
+#include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/safe_integer_conversions.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
namespace gfx {
diff --git a/chromium/ui/gfx/geometry/size_conversions.h b/chromium/ui/gfx/geometry/size_conversions.h
new file mode 100644
index 00000000000..96fb79f93c2
--- /dev/null
+++ b/chromium/ui/gfx/geometry/size_conversions.h
@@ -0,0 +1,24 @@
+// 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_CONVERSIONS_H_
+#define UI_GFX_GEOMETRY_SIZE_CONVERSIONS_H_
+
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_f.h"
+
+namespace gfx {
+
+// Returns a Size with each component from the input SizeF floored.
+GFX_EXPORT Size ToFlooredSize(const SizeF& size);
+
+// Returns a Size with each component from the input SizeF ceiled.
+GFX_EXPORT Size ToCeiledSize(const SizeF& size);
+
+// Returns a Size with each component from the input SizeF rounded.
+GFX_EXPORT Size ToRoundedSize(const SizeF& size);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_SIZE_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/size_f.cc b/chromium/ui/gfx/geometry/size_f.cc
index 6eba8849b22..10c144575e7 100644
--- a/chromium/ui/gfx/size_f.cc
+++ b/chromium/ui/gfx/geometry/size_f.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/size_f.h"
+#include "ui/gfx/geometry/size_f.h"
#include "base/strings/stringprintf.h"
diff --git a/chromium/ui/gfx/geometry/size_f.h b/chromium/ui/gfx/geometry/size_f.h
new file mode 100644
index 00000000000..8ec5628e62d
--- /dev/null
+++ b/chromium/ui/gfx/geometry/size_f.h
@@ -0,0 +1,54 @@
+// 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_F_H_
+#define UI_GFX_GEOMETRY_SIZE_F_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "ui/gfx/geometry/size_base.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// A floating version of gfx::Size.
+class GFX_EXPORT SizeF : public SizeBase<SizeF, float> {
+ public:
+ SizeF() : SizeBase<SizeF, float>(0, 0) {}
+ SizeF(float width, float height) : SizeBase<SizeF, float>(width, height) {}
+ ~SizeF() {}
+
+ void Scale(float scale) {
+ Scale(scale, scale);
+ }
+
+ void Scale(float x_scale, float y_scale) {
+ SetSize(width() * x_scale, height() * y_scale);
+ }
+
+ std::string ToString() const;
+};
+
+inline 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) {
+ return !(lhs == rhs);
+}
+
+GFX_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);
+}
+
+#if !defined(COMPILER_MSVC)
+extern template class SizeBase<SizeF, float>;
+#endif
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_SIZE_F_H_
diff --git a/chromium/ui/gfx/size_unittest.cc b/chromium/ui/gfx/geometry/size_unittest.cc
index 9f109b3f04b..15892833307 100644
--- a/chromium/ui/gfx/size_unittest.cc
+++ b/chromium/ui/gfx/geometry/size_unittest.cc
@@ -2,12 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/size_base.h"
-
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/size.h"
-#include "ui/gfx/size_conversions.h"
-#include "ui/gfx/size_f.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/geometry/size_base.h"
+#include "ui/gfx/geometry/size_conversions.h"
+#include "ui/gfx/geometry/size_f.h"
namespace gfx {
diff --git a/chromium/ui/gfx/vector2d.cc b/chromium/ui/gfx/geometry/vector2d.cc
index 9e685e45d1d..d9f57fd3b10 100644
--- a/chromium/ui/gfx/vector2d.cc
+++ b/chromium/ui/gfx/geometry/vector2d.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/vector2d.h"
+#include "ui/gfx/geometry/vector2d.h"
#include <cmath>
diff --git a/chromium/ui/gfx/geometry/vector2d.h b/chromium/ui/gfx/geometry/vector2d.h
new file mode 100644
index 00000000000..12f29a956d7
--- /dev/null
+++ b/chromium/ui/gfx/geometry/vector2d.h
@@ -0,0 +1,91 @@
+// 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.
+
+// Defines a simple integer vector class. This class is used to indicate a
+// distance in two dimensions between two points. Subtracting two points should
+// produce a vector, and adding a vector to a point produces the point at the
+// vector's distance from the original point.
+
+#ifndef UI_GFX_GEOMETRY_VECTOR2D_H_
+#define UI_GFX_GEOMETRY_VECTOR2D_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+class GFX_EXPORT Vector2d {
+ public:
+ Vector2d() : x_(0), y_(0) {}
+ Vector2d(int x, int y) : x_(x), y_(y) {}
+
+ int x() const { return x_; }
+ void set_x(int x) { x_ = x; }
+
+ int y() const { return y_; }
+ void set_y(int y) { y_ = y; }
+
+ // True if both components of the vector are 0.
+ bool IsZero() const;
+
+ // Add the components of the |other| vector to the current vector.
+ void Add(const Vector2d& other);
+ // Subtract the components of the |other| vector from the current vector.
+ void Subtract(const Vector2d& other);
+
+ 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_;
+ }
+
+ void SetToMax(const Vector2d& other) {
+ x_ = x_ >= other.x_ ? x_ : other.x_;
+ y_ = y_ >= other.y_ ? 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;
+ // Gives the diagonal length of the vector.
+ float Length() const;
+
+ std::string ToString() const;
+
+ operator Vector2dF() const { return Vector2dF(x_, y_); }
+
+ private:
+ int x_;
+ 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());
+}
+
+inline Vector2d operator+(const Vector2d& lhs, const Vector2d& rhs) {
+ Vector2d result = lhs;
+ result.Add(rhs);
+ return result;
+}
+
+inline Vector2d operator-(const Vector2d& lhs, const Vector2d& rhs) {
+ Vector2d result = lhs;
+ result.Add(-rhs);
+ return result;
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_VECTOR2D_H_
diff --git a/chromium/ui/gfx/vector2d_conversions.cc b/chromium/ui/gfx/geometry/vector2d_conversions.cc
index 457e9f708a2..dceb69e2ffe 100644
--- a/chromium/ui/gfx/vector2d_conversions.cc
+++ b/chromium/ui/gfx/geometry/vector2d_conversions.cc
@@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/vector2d_conversions.h"
+#include "ui/gfx/geometry/vector2d_conversions.h"
-#include "ui/gfx/safe_integer_conversions.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
namespace gfx {
diff --git a/chromium/ui/gfx/geometry/vector2d_conversions.h b/chromium/ui/gfx/geometry/vector2d_conversions.h
new file mode 100644
index 00000000000..f4e16ae4be7
--- /dev/null
+++ b/chromium/ui/gfx/geometry/vector2d_conversions.h
@@ -0,0 +1,24 @@
+// 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_VECTOR2D_CONVERSIONS_H_
+#define UI_GFX_GEOMETRY_VECTOR2D_CONVERSIONS_H_
+
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace gfx {
+
+// Returns a Vector2d with each component from the input Vector2dF floored.
+GFX_EXPORT Vector2d ToFlooredVector2d(const Vector2dF& vector2d);
+
+// Returns a Vector2d with each component from the input Vector2dF ceiled.
+GFX_EXPORT Vector2d ToCeiledVector2d(const Vector2dF& vector2d);
+
+// Returns a Vector2d with each component from the input Vector2dF rounded.
+GFX_EXPORT Vector2d ToRoundedVector2d(const Vector2dF& vector2d);
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_VECTOR2D_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/vector2d_f.cc b/chromium/ui/gfx/geometry/vector2d_f.cc
index 2ad267074b3..ccb15ae0c4c 100644
--- a/chromium/ui/gfx/vector2d_f.cc
+++ b/chromium/ui/gfx/geometry/vector2d_f.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/vector2d_f.h"
+#include "ui/gfx/geometry/vector2d_f.h"
#include <cmath>
diff --git a/chromium/ui/gfx/geometry/vector2d_f.h b/chromium/ui/gfx/geometry/vector2d_f.h
new file mode 100644
index 00000000000..4bab99e5825
--- /dev/null
+++ b/chromium/ui/gfx/geometry/vector2d_f.h
@@ -0,0 +1,112 @@
+// 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.
+
+// Defines a simple float vector class. This class is used to indicate a
+// distance in two dimensions between two points. Subtracting two points should
+// produce a vector, and adding a vector to a point produces the point at the
+// vector's distance from the original point.
+
+#ifndef UI_GFX_GEOMETRY_VECTOR2D_F_H_
+#define UI_GFX_GEOMETRY_VECTOR2D_F_H_
+
+#include <string>
+
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+class GFX_EXPORT Vector2dF {
+ public:
+ Vector2dF() : x_(0), y_(0) {}
+ Vector2dF(float x, float y) : x_(x), y_(y) {}
+
+ float x() const { return x_; }
+ void set_x(float x) { x_ = x; }
+
+ float y() const { return y_; }
+ void set_y(float y) { y_ = y; }
+
+ // True if both components of the vector are 0.
+ bool IsZero() const;
+
+ // Add the components of the |other| vector to the current vector.
+ void Add(const Vector2dF& other);
+ // Subtract the components of the |other| vector from the current vector.
+ void Subtract(const Vector2dF& other);
+
+ void operator+=(const Vector2dF& other) { Add(other); }
+ void operator-=(const Vector2dF& other) { Subtract(other); }
+
+ void SetToMin(const Vector2dF& other) {
+ x_ = x_ <= other.x_ ? x_ : other.x_;
+ y_ = y_ <= other.y_ ? y_ : other.y_;
+ }
+
+ void SetToMax(const Vector2dF& other) {
+ x_ = x_ >= other.x_ ? x_ : other.x_;
+ y_ = y_ >= other.y_ ? y_ : other.y_;
+ }
+
+ // Gives the square of the diagonal length of the vector.
+ double LengthSquared() const;
+ // Gives the diagonal length of the vector.
+ float Length() 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);
+
+ std::string ToString() const;
+
+ private:
+ float x_;
+ float y_;
+};
+
+inline 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) {
+ return !(lhs == rhs);
+}
+
+inline Vector2dF operator-(const Vector2dF& v) {
+ return Vector2dF(-v.x(), -v.y());
+}
+
+inline Vector2dF operator+(const Vector2dF& lhs, const Vector2dF& rhs) {
+ Vector2dF result = lhs;
+ result.Add(rhs);
+ return result;
+}
+
+inline Vector2dF operator-(const Vector2dF& lhs, const Vector2dF& rhs) {
+ Vector2dF result = lhs;
+ result.Add(-rhs);
+ return result;
+}
+
+// Return the cross product of two vectors.
+GFX_EXPORT double CrossProduct(const Vector2dF& lhs, const Vector2dF& rhs);
+
+// Return the dot product of two vectors.
+GFX_EXPORT double DotProduct(const Vector2dF& lhs, const Vector2dF& rhs);
+
+// Return a vector that is |v| scaled by the given scale factors along each
+// axis.
+GFX_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);
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_VECTOR2D_F_H_
diff --git a/chromium/ui/gfx/vector2d_unittest.cc b/chromium/ui/gfx/geometry/vector2d_unittest.cc
index 5d9e21ea66d..38af69405f5 100644
--- a/chromium/ui/gfx/vector2d_unittest.cc
+++ b/chromium/ui/gfx/geometry/vector2d_unittest.cc
@@ -7,8 +7,8 @@
#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/vector2d.h"
-#include "ui/gfx/vector2d_f.h"
+#include "ui/gfx/geometry/vector2d.h"
+#include "ui/gfx/geometry/vector2d_f.h"
namespace gfx {
diff --git a/chromium/ui/gfx/vector3d_f.cc b/chromium/ui/gfx/geometry/vector3d_f.cc
index 233e0542673..a30f9db5cbe 100644
--- a/chromium/ui/gfx/vector3d_f.cc
+++ b/chromium/ui/gfx/geometry/vector3d_f.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/vector3d_f.h"
+#include "ui/gfx/geometry/vector3d_f.h"
#include <cmath>
diff --git a/chromium/ui/gfx/geometry/vector3d_f.h b/chromium/ui/gfx/geometry/vector3d_f.h
new file mode 100644
index 00000000000..8f8b75d91e7
--- /dev/null
+++ b/chromium/ui/gfx/geometry/vector3d_f.h
@@ -0,0 +1,124 @@
+// 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.
+
+// Defines a simple float vector class. This class is used to indicate a
+// distance in two dimensions between two points. Subtracting two points should
+// produce a vector, and adding a vector to a point produces the point at the
+// vector's distance from the original point.
+
+#ifndef UI_GFX_GEOMETRY_VECTOR3D_F_H_
+#define UI_GFX_GEOMETRY_VECTOR3D_F_H_
+
+#include <string>
+
+#include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+class GFX_EXPORT Vector3dF {
+ public:
+ Vector3dF();
+ Vector3dF(float x, float y, float z);
+
+ explicit Vector3dF(const Vector2dF& other);
+
+ float x() const { return x_; }
+ void set_x(float x) { x_ = x; }
+
+ float y() const { return y_; }
+ void set_y(float y) { y_ = y; }
+
+ float z() const { return z_; }
+ void set_z(float z) { z_ = z; }
+
+ // True if all components of the vector are 0.
+ bool IsZero() const;
+
+ // Add the components of the |other| vector to the current vector.
+ void Add(const Vector3dF& other);
+ // Subtract the components of the |other| vector from the current vector.
+ void Subtract(const Vector3dF& other);
+
+ void operator+=(const Vector3dF& other) { Add(other); }
+ void operator-=(const Vector3dF& other) { Subtract(other); }
+
+ void SetToMin(const Vector3dF& other) {
+ x_ = x_ <= other.x_ ? x_ : other.x_;
+ y_ = y_ <= other.y_ ? y_ : other.y_;
+ z_ = z_ <= other.z_ ? z_ : other.z_;
+ }
+
+ void SetToMax(const Vector3dF& other) {
+ x_ = x_ >= other.x_ ? x_ : other.x_;
+ y_ = y_ >= other.y_ ? y_ : other.y_;
+ z_ = z_ >= other.z_ ? z_ : other.z_;
+ }
+
+ // Gives the square of the diagonal length of the vector.
+ double LengthSquared() const;
+ // Gives the diagonal length of the vector.
+ float Length() const;
+
+ // Scale all components of the vector by |scale|.
+ void Scale(float scale) { Scale(scale, scale, scale); }
+ // Scale the each component of the vector by the given scale factors.
+ void Scale(float x_scale, float y_scale, float z_scale);
+
+ // Take the cross product of this vector with |other| and become the result.
+ void Cross(const Vector3dF& other);
+
+ std::string ToString() const;
+
+ private:
+ float x_;
+ float y_;
+ float z_;
+};
+
+inline bool operator==(const Vector3dF& lhs, const Vector3dF& rhs) {
+ return lhs.x() == rhs.x() && lhs.y() == rhs.y() && lhs.z() == rhs.z();
+}
+
+inline Vector3dF operator-(const Vector3dF& v) {
+ return Vector3dF(-v.x(), -v.y(), -v.z());
+}
+
+inline Vector3dF operator+(const Vector3dF& lhs, const Vector3dF& rhs) {
+ Vector3dF result = lhs;
+ result.Add(rhs);
+ return result;
+}
+
+inline Vector3dF operator-(const Vector3dF& lhs, const Vector3dF& rhs) {
+ Vector3dF result = lhs;
+ result.Add(-rhs);
+ return result;
+}
+
+// Return the cross product of two vectors.
+inline Vector3dF CrossProduct(const Vector3dF& lhs, const Vector3dF& rhs) {
+ Vector3dF result = lhs;
+ result.Cross(rhs);
+ return result;
+}
+
+// Return the dot product of two vectors.
+GFX_EXPORT float DotProduct(const Vector3dF& lhs, const Vector3dF& rhs);
+
+// Return a vector that is |v| scaled by the given scale factors along each
+// axis.
+GFX_EXPORT Vector3dF ScaleVector3d(const Vector3dF& v,
+ float x_scale,
+ float y_scale,
+ float z_scale);
+
+// Return a vector that is |v| scaled by the given scale factor.
+inline Vector3dF ScaleVector3d(const Vector3dF& v, float scale) {
+ return ScaleVector3d(v, scale, scale, scale);
+}
+
+} // namespace gfx
+
+#endif // UI_GFX_GEOMETRY_VECTOR3D_F_H_
diff --git a/chromium/ui/gfx/vector3d_unittest.cc b/chromium/ui/gfx/geometry/vector3d_unittest.cc
index 5b3bd7e91bf..d5ec8d6700c 100644
--- a/chromium/ui/gfx/vector3d_unittest.cc
+++ b/chromium/ui/gfx/geometry/vector3d_unittest.cc
@@ -7,7 +7,7 @@
#include "base/basictypes.h"
#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/vector3d_f.h"
+#include "ui/gfx/geometry/vector3d_f.h"
namespace gfx {
diff --git a/chromium/ui/gfx/gfx.gyp b/chromium/ui/gfx/gfx.gyp
index 5fb17d52ee6..3077ac90c18 100644
--- a/chromium/ui/gfx/gfx.gyp
+++ b/chromium/ui/gfx/gfx.gyp
@@ -8,6 +8,67 @@
},
'targets': [
{
+ 'target_name': 'gfx_geometry',
+ 'type': '<(component)',
+ 'dependencies': [
+ '<(DEPTH)/base/base.gyp:base',
+ ],
+ 'defines': [
+ 'GFX_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'geometry/box_f.cc',
+ 'geometry/box_f.h',
+ 'geometry/cubic_bezier.h',
+ 'geometry/cubic_bezier.cc',
+ 'geometry/insets.cc',
+ 'geometry/insets.h',
+ 'geometry/insets_base.h',
+ 'geometry/insets_f.cc',
+ 'geometry/insets_f.h',
+ 'geometry/matrix3_f.cc',
+ 'geometry/matrix3_f.h',
+ 'geometry/point.cc',
+ 'geometry/point.h',
+ 'geometry/point3_f.cc',
+ 'geometry/point3_f.h',
+ 'geometry/point_base.h',
+ 'geometry/point_conversions.cc',
+ 'geometry/point_conversions.h',
+ 'geometry/point_f.cc',
+ 'geometry/point_f.h',
+ 'geometry/quad_f.cc',
+ 'geometry/quad_f.h',
+ 'geometry/rect.cc',
+ 'geometry/rect.h',
+ 'geometry/rect_base.h',
+ 'geometry/rect_base_impl.h',
+ 'geometry/rect_conversions.cc',
+ 'geometry/rect_conversions.h',
+ 'geometry/rect_f.cc',
+ 'geometry/rect_f.h',
+ 'geometry/r_tree.h',
+ 'geometry/r_tree_base.cc',
+ 'geometry/r_tree_base.h',
+ 'geometry/safe_integer_conversions.h',
+ 'geometry/size.cc',
+ 'geometry/size.h',
+ 'geometry/size_base.h',
+ 'geometry/size_conversions.cc',
+ 'geometry/size_conversions.h',
+ 'geometry/size_f.cc',
+ 'geometry/size_f.h',
+ 'geometry/vector2d.cc',
+ 'geometry/vector2d.h',
+ 'geometry/vector2d_conversions.cc',
+ 'geometry/vector2d_conversions.h',
+ 'geometry/vector2d_f.cc',
+ 'geometry/vector2d_f.h',
+ 'geometry/vector3d_f.cc',
+ 'geometry/vector3d_f.h',
+ ],
+ },
+ {
'target_name': 'gfx',
'type': '<(component)',
'dependencies': [
@@ -15,13 +76,13 @@
'<(DEPTH)/base/base.gyp:base_i18n',
'<(DEPTH)/base/base.gyp:base_static',
'<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
- '<(DEPTH)/net/net.gyp:net',
'<(DEPTH)/skia/skia.gyp:skia',
+ '<(DEPTH)/third_party/harfbuzz-ng/harfbuzz.gyp:harfbuzz-ng',
'<(DEPTH)/third_party/icu/icu.gyp:icui18n',
'<(DEPTH)/third_party/icu/icu.gyp:icuuc',
'<(DEPTH)/third_party/libpng/libpng.gyp:libpng',
'<(DEPTH)/third_party/zlib/zlib.gyp:zlib',
- '<(DEPTH)/url/url.gyp:url_lib',
+ 'gfx_geometry',
],
# text_elider.h includes ICU headers.
'export_dependent_settings': [
@@ -32,6 +93,9 @@
'defines': [
'GFX_IMPLEMENTATION',
],
+ 'include_dirs': [
+ '<(DEPTH)/third_party/icu/source/common'
+ ],
'sources': [
'android/device_display_info.cc',
'android/device_display_info.h',
@@ -39,6 +103,8 @@
'android/gfx_jni_registrar.h',
'android/java_bitmap.cc',
'android/java_bitmap.h',
+ 'android/scroller.cc',
+ 'android/scroller.h',
'android/shared_device_display_info.cc',
'android/shared_device_display_info.h',
'android/view_configuration.cc',
@@ -62,14 +128,10 @@
'animation/tween.h',
'blit.cc',
'blit.h',
- 'box_f.cc',
- 'box_f.h',
'break_list.h',
'canvas.cc',
'canvas.h',
'canvas_android.cc',
- 'canvas_paint_gtk.cc',
- 'canvas_paint_gtk.h',
'canvas_paint_mac.h',
'canvas_paint_mac.mm',
'canvas_paint_win.cc',
@@ -84,7 +146,7 @@
'color_analysis.h',
'color_profile.cc',
'color_profile.h',
- 'color_profile_mac.cc',
+ 'color_profile_mac.mm',
'color_profile_win.cc',
'color_utils.cc',
'color_utils.h',
@@ -94,18 +156,20 @@
'display_observer.h',
'favicon_size.cc',
'favicon_size.h',
- 'frame_time.h',
'font.cc',
'font.h',
'font_fallback_win.cc',
'font_fallback_win.h',
'font_list.cc',
'font_list.h',
+ 'font_list_impl.cc',
+ 'font_list_impl.h',
'font_render_params_android.cc',
'font_render_params_linux.cc',
'font_render_params_linux.h',
'font_smoothing_win.cc',
'font_smoothing_win.h',
+ 'frame_time.h',
'gfx_export.h',
'gfx_paths.cc',
'gfx_paths.h',
@@ -135,39 +199,20 @@
'image/image_util.cc',
'image/image_util.h',
'image/image_util_ios.mm',
- 'insets.cc',
- 'insets.h',
- 'insets_base.h',
- 'insets_f.cc',
- 'insets_f.h',
'interpolated_transform.cc',
'interpolated_transform.h',
+ 'linux_font_delegate.cc',
+ 'linux_font_delegate.h',
'mac/scoped_ns_disable_screen_updates.h',
- 'matrix3_f.cc',
- 'matrix3_f.h',
'native_widget_types.h',
- 'ozone/dri/dri_skbitmap.cc',
- 'ozone/dri/dri_skbitmap.h',
- 'ozone/dri/dri_surface.cc',
- 'ozone/dri/dri_surface.h',
- 'ozone/dri/dri_surface_factory.cc',
- 'ozone/dri/dri_surface_factory.h',
- 'ozone/dri/dri_vsync_provider.cc',
- 'ozone/dri/dri_vsync_provider.h',
- 'ozone/dri/dri_wrapper.cc',
- 'ozone/dri/dri_wrapper.h',
- 'ozone/dri/hardware_display_controller.cc',
- 'ozone/dri/hardware_display_controller.h',
- 'ozone/impl/file_surface_factory.cc',
- 'ozone/impl/file_surface_factory.h',
- 'ozone/surface_factory_ozone.cc',
- 'ozone/surface_factory_ozone.h',
+ 'nine_image_painter.cc',
+ 'nine_image_painter.h',
+ 'overlay_transform.h',
'pango_util.cc',
'pango_util.h',
'path.cc',
'path.h',
'path_aura.cc',
- 'path_gtk.cc',
'path_win.cc',
'path_win.h',
'path_x11.cc',
@@ -183,31 +228,14 @@
'platform_font_pango.h',
'platform_font_win.cc',
'platform_font_win.h',
- 'point.cc',
- 'point.h',
- 'point3_f.cc',
- 'point3_f.h',
- 'point_base.h',
- 'point_conversions.cc',
- 'point_conversions.h',
- 'point_f.cc',
- 'point_f.h',
- 'quad_f.cc',
- 'quad_f.h',
'range/range.cc',
'range/range.h',
'range/range_mac.mm',
'range/range_win.cc',
- 'rect.cc',
- 'rect.h',
- 'rect_base.h',
- 'rect_base_impl.h',
- 'rect_conversions.cc',
- 'rect_conversions.h',
- 'rect_f.cc',
- 'rect_f.h',
'render_text.cc',
'render_text.h',
+ 'render_text_harfbuzz.cc',
+ 'render_text_harfbuzz.h',
'render_text_mac.cc',
'render_text_mac.h',
'render_text_ozone.cc',
@@ -215,7 +243,6 @@
'render_text_pango.h',
'render_text_win.cc',
'render_text_win.h',
- 'safe_integer_conversions.h',
'scoped_canvas.h',
'scoped_cg_context_save_gstate_mac.h',
'scoped_ns_graphics_context_save_gstate_mac.h',
@@ -226,7 +253,6 @@
'screen.h',
'screen_android.cc',
'screen_aura.cc',
- 'screen_gtk.cc',
'screen_ios.mm',
'screen_mac.mm',
'screen_win.cc',
@@ -239,19 +265,10 @@
'sequential_id_generator.h',
'shadow_value.cc',
'shadow_value.h',
- 'size.cc',
- 'size.h',
- 'size_base.h',
- 'size_conversions.cc',
- 'size_conversions.h',
- 'size_f.cc',
- 'size_f.h',
'skbitmap_operations.cc',
'skbitmap_operations.h',
'skia_util.cc',
'skia_util.h',
- 'skia_utils_gtk.cc',
- 'skia_utils_gtk.h',
'switches.cc',
'switches.h',
'sys_color_change_listener.cc',
@@ -271,14 +288,6 @@
'ui_gfx_exports.cc',
'utf16_indexing.cc',
'utf16_indexing.h',
- 'vector2d.cc',
- 'vector2d.h',
- 'vector2d_conversions.cc',
- 'vector2d_conversions.h',
- 'vector2d_f.cc',
- 'vector2d_f.h',
- 'vector3d_f.cc',
- 'vector3d_f.h',
'vsync_provider.h',
'win/dpi.cc',
'win/dpi.h',
@@ -289,10 +298,6 @@
'win/singleton_hwnd.h',
'win/window_impl.cc',
'win/window_impl.h',
- 'x/x11_atom_cache.cc',
- 'x/x11_atom_cache.h',
- 'x/x11_types.cc',
- 'x/x11_types.h',
],
'conditions': [
['OS=="ios"', {
@@ -316,24 +321,6 @@
'canvas_skia.cc',
],
}],
- ['toolkit_uses_gtk == 1', {
- 'dependencies': [
- '<(DEPTH)/build/linux/system.gyp:gtk',
- ],
- 'sources': [
- 'gtk_native_view_id_manager.cc',
- 'gtk_native_view_id_manager.h',
- 'gtk_preserve_window.cc',
- 'gtk_preserve_window.h',
- 'gdk_compat.h',
- 'gtk_compat.h',
- 'gtk_util.cc',
- 'gtk_util.h',
- 'image/cairo_cached_surface.cc',
- 'image/cairo_cached_surface.h',
- 'scoped_gobject.h',
- ],
- }],
['OS=="win"', {
'sources': [
'gdi_util.cc',
@@ -350,7 +337,6 @@
'sources!': [
'animation/throb_animation.cc',
'display_observer.cc',
- 'path.cc',
'selection_model.cc',
],
'dependencies': [
@@ -363,6 +349,22 @@
],
},
}],
+ ['use_aura==0 and toolkit_views==0', {
+ 'sources!': [
+ 'nine_image_painter.cc',
+ 'nine_image_painter.h',
+ ],
+ }],
+ ['OS=="android" and use_aura==0', {
+ 'sources!': [
+ 'path.cc',
+ ],
+ }],
+ ['OS=="android" and use_aura==1', {
+ 'sources!': [
+ 'screen_android.cc',
+ ],
+ }],
['OS=="android" and android_webview_build==0', {
'dependencies': [
'<(DEPTH)/base/base.gyp:base_java',
@@ -372,9 +374,17 @@
'sources!': [
'render_text.cc',
'render_text.h',
+ 'render_text_harfbuzz.cc',
+ 'render_text_harfbuzz.h',
'text_utils_skia.cc',
],
}],
+ ['use_x11==1', {
+ 'dependencies': [
+ '../../build/linux/system.gyp:x11',
+ 'x/gfx_x11.gyp:gfx_x11',
+ ],
+ }],
['use_pango==1', {
'dependencies': [
'<(DEPTH)/build/linux/system.gyp:pangocairo',
@@ -384,9 +394,10 @@
'render_text_ozone.cc',
],
}],
- ['ozone_platform_dri==1', {
+ ['desktop_linux==1 or chromeos==1', {
'dependencies': [
- '<(DEPTH)/build/linux/system.gyp:dridrm',
+ # font_render_params_linux.cc uses fontconfig
+ '<(DEPTH)/build/linux/system.gyp:fontconfig',
],
}],
],
@@ -399,38 +410,58 @@
],
}],
],
- }
+ },
+ {
+ 'target_name': 'gfx_test_support',
+ 'sources': [
+ 'test/gfx_util.cc',
+ 'test/gfx_util.h',
+ 'test/ui_cocoa_test_helper.h',
+ 'test/ui_cocoa_test_helper.mm',
+ ],
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../skia/skia.gyp:skia',
+ '../../testing/gtest.gyp:gtest',
+ ],
+ 'conditions': [
+ ['OS == "mac"', {
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/AppKit.framework',
+ ],
+ },
+ }],
+ ['OS!="ios"', {
+ 'type': 'static_library',
+ }, { # OS=="ios"
+ # None of the sources in this target are built on iOS, resulting in
+ # link errors when building targets that depend on this target
+ # because the static library isn't found. If this target is changed
+ # to have sources that are built on iOS, the target should be changed
+ # to be of type static_library on all platforms.
+ 'type': 'none',
+ # The cocoa files don't apply to iOS.
+ 'sources/': [
+ ['exclude', 'cocoa']
+ ],
+ }],
+ ],
+ },
],
'conditions': [
['OS=="android"' , {
'targets': [
{
- 'target_name': 'gfx_view_jni_headers',
- 'type': 'none',
- 'variables': {
- 'jni_gen_package': 'ui/gfx',
- 'input_java_class': 'android/view/ViewConfiguration.class',
- },
- 'includes': [ '../../build/jar_file_jni_generator.gypi' ],
- },
- {
'target_name': 'gfx_jni_headers',
'type': 'none',
- 'dependencies': [
- 'gfx_view_jni_headers'
- ],
- 'direct_dependent_settings': {
- 'include_dirs': [
- '<(SHARED_INTERMEDIATE_DIR)/ui/gfx',
- ],
- },
'sources': [
'../android/java/src/org/chromium/ui/gfx/BitmapHelper.java',
'../android/java/src/org/chromium/ui/gfx/DeviceDisplayInfo.java',
+ '../android/java/src/org/chromium/ui/gfx/ViewConfigurationHelper.java',
],
'variables': {
'jni_gen_package': 'ui/gfx',
- 'jni_generator_ptr_type': 'long'
},
'includes': [ '../../build/jni_generator.gypi' ],
},
diff --git a/chromium/ui/gfx/gfx_tests.gyp b/chromium/ui/gfx/gfx_tests.gyp
new file mode 100644
index 00000000000..dda6d142ef3
--- /dev/null
+++ b/chromium/ui/gfx/gfx_tests.gyp
@@ -0,0 +1,146 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'gfx_unittests',
+ 'type': '<(gtest_target_type)',
+ # iOS uses a small subset of ui. common_sources are the only files that
+ # are built on iOS.
+ 'common_sources' : [
+ 'font_unittest.cc',
+ 'image/image_family_unittest.cc',
+ 'image/image_skia_unittest.cc',
+ 'image/image_unittest.cc',
+ 'image/image_unittest_util.cc',
+ 'image/image_unittest_util.h',
+ 'image/image_unittest_util_ios.mm',
+ 'image/image_unittest_util_mac.mm',
+ 'test/run_all_unittests.cc',
+ 'text_elider_unittest.cc',
+ 'text_utils_unittest.cc',
+ ],
+ 'all_sources': [
+ '<@(_common_sources)',
+ 'animation/animation_container_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_utils_unittest.cc',
+ 'display_unittest.cc',
+ 'font_list_unittest.cc',
+ 'geometry/box_unittest.cc',
+ 'geometry/cubic_bezier_unittest.cc',
+ 'geometry/insets_unittest.cc',
+ 'geometry/matrix3_unittest.cc',
+ 'geometry/point_unittest.cc',
+ 'geometry/point3_unittest.cc',
+ 'geometry/quad_unittest.cc',
+ 'geometry/r_tree_unittest.cc',
+ 'geometry/rect_unittest.cc',
+ 'geometry/safe_integer_conversions_unittest.cc',
+ 'geometry/size_unittest.cc',
+ 'geometry/vector2d_unittest.cc',
+ 'geometry/vector3d_unittest.cc',
+ 'image/image_mac_unittest.mm',
+ 'image/image_util_unittest.cc',
+ 'range/range_mac_unittest.mm',
+ 'range/range_unittest.cc',
+ 'range/range_win_unittest.cc',
+ 'sequential_id_generator_unittest.cc',
+ 'shadow_value_unittest.cc',
+ 'skbitmap_operations_unittest.cc',
+ 'skrect_conversion_unittest.cc',
+ 'transform_util_unittest.cc',
+ 'utf16_indexing_unittest.cc',
+ ],
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../base/base.gyp:test_support_base',
+ '../../skia/skia.gyp:skia',
+ '../../testing/gtest.gyp:gtest',
+ '../../third_party/libpng/libpng.gyp:libpng',
+ '../base/ui_base.gyp:ui_base',
+ 'gfx.gyp:gfx',
+ 'gfx.gyp:gfx_geometry',
+ 'gfx.gyp:gfx_test_support',
+ ],
+ 'conditions': [
+ ['OS == "ios"', {
+ 'sources': ['<@(_common_sources)'],
+ }, { # OS != "ios"
+ 'sources': ['<@(_all_sources)'],
+ }],
+ ['OS == "win"', {
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [ 4267, ],
+ }],
+ ['OS != "mac" and OS != "ios"', {
+ 'sources': [
+ 'transform_unittest.cc',
+ 'interpolated_transform_unittest.cc',
+ ],
+ }],
+ ['use_pango == 1', {
+ 'dependencies': [
+ '../../build/linux/system.gyp:fontconfig',
+ '../../build/linux/system.gyp:pangocairo',
+ ],
+ 'sources': [
+ 'platform_font_pango_unittest.cc',
+ ],
+ 'conditions': [
+ ['use_allocator!="none"', {
+ 'dependencies': [
+ '../../base/allocator/allocator.gyp:allocator',
+ ],
+ }],
+ ],
+ }],
+ ['use_ozone==1 and use_pango==0', {
+ 'sources!': [
+ 'canvas_unittest.cc',
+ 'font_list_unittest.cc',
+ 'font_unittest.cc',
+ 'text_elider_unittest.cc',
+ ],
+ }],
+ ['OS == "android"', {
+ 'dependencies': [
+ '../../testing/android/native_test.gyp:native_test_native_code',
+ ],
+ }],
+ ],
+ }
+ ],
+ 'conditions': [
+ ['OS == "android"', {
+ 'targets': [
+ {
+ 'target_name': 'gfx_unittests_apk',
+ 'type': 'none',
+ 'dependencies': [
+ '../android/ui_android.gyp:ui_java',
+ 'gfx_unittests',
+ ],
+ 'variables': {
+ 'test_suite_name': 'gfx_unittests',
+ },
+ 'includes': [ '../../build/apk_test.gypi' ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/chromium/ui/gfx/gpu_memory_buffer.cc b/chromium/ui/gfx/gpu_memory_buffer.cc
index c1de26c374b..057e8c7575a 100644
--- a/chromium/ui/gfx/gpu_memory_buffer.cc
+++ b/chromium/ui/gfx/gpu_memory_buffer.cc
@@ -6,6 +6,20 @@
namespace gfx {
+GpuMemoryBufferHandle::GpuMemoryBufferHandle()
+ : type(EMPTY_BUFFER),
+ handle(base::SharedMemory::NULLHandle())
+#if defined(OS_MACOSX)
+ ,
+ io_surface_id(0u)
+#endif
+#if defined(OS_ANDROID)
+ ,
+ native_buffer(NULL)
+#endif
+{
+}
+
GpuMemoryBuffer::GpuMemoryBuffer() {}
GpuMemoryBuffer::~GpuMemoryBuffer() {}
diff --git a/chromium/ui/gfx/gpu_memory_buffer.h b/chromium/ui/gfx/gpu_memory_buffer.h
index 4a7b142d175..1a622016c7c 100644
--- a/chromium/ui/gfx/gpu_memory_buffer.h
+++ b/chromium/ui/gfx/gpu_memory_buffer.h
@@ -18,61 +18,63 @@ namespace gfx {
enum GpuMemoryBufferType {
EMPTY_BUFFER,
SHARED_MEMORY_BUFFER,
- EGL_CLIENT_BUFFER,
- IO_SURFACE_BUFFER
+ IO_SURFACE_BUFFER,
+ ANDROID_NATIVE_BUFFER,
+ SURFACE_TEXTURE_BUFFER,
+ GPU_MEMORY_BUFFER_TYPE_LAST = SURFACE_TEXTURE_BUFFER
};
-struct GpuMemoryBufferHandle {
- GpuMemoryBufferHandle()
- : type(EMPTY_BUFFER),
- handle(base::SharedMemory::NULLHandle())
+// TODO(alexst): Merge this with GpuMemoryBufferId as part of switchover to
+// the new API for GpuMemoryBuffer allocation when it's done.
#if defined(OS_ANDROID)
- , native_buffer(NULL)
-#endif
-#if defined(OS_MACOSX)
- , io_surface_id(0)
+struct SurfaceTextureId {
+ SurfaceTextureId() : primary_id(0), secondary_id(0) {}
+ SurfaceTextureId(int32 primary_id, int32 secondary_id)
+ : primary_id(primary_id), secondary_id(secondary_id) {}
+ int32 primary_id;
+ int32 secondary_id;
+};
#endif
- {
- }
+
+struct GpuMemoryBufferId {
+ GpuMemoryBufferId() : primary_id(0), secondary_id(0) {}
+ GpuMemoryBufferId(int32 primary_id, int32 secondary_id)
+ : primary_id(primary_id), secondary_id(secondary_id) {}
+ int32 primary_id;
+ int32 secondary_id;
+};
+
+struct GFX_EXPORT GpuMemoryBufferHandle {
+ GpuMemoryBufferHandle();
bool is_null() const { return type == EMPTY_BUFFER; }
GpuMemoryBufferType type;
base::SharedMemoryHandle handle;
-#if defined(OS_ANDROID)
- EGLClientBuffer native_buffer;
-#endif
+ GpuMemoryBufferId global_id;
#if defined(OS_MACOSX)
uint32 io_surface_id;
#endif
-
+#if defined(OS_ANDROID)
+ EGLClientBuffer native_buffer;
+ SurfaceTextureId surface_texture_id;
+#endif
};
-// Interface for creating and accessing a zero-copy GPU memory buffer.
-// This design evolved from the generalization of GraphicBuffer API
-// of Android framework.
-//
-// THREADING CONSIDERATIONS:
-//
-// This interface is thread-safe. However, multiple threads mapping
-// a buffer for Write or ReadOrWrite simultaneously may result in undefined
-// behavior and is not allowed.
+// This interface typically correspond to a type of shared memory that is also
+// shared with the GPU. A GPU memory buffer can be written to directly by
+// regular CPU code, but can also be read by the GPU.
class GFX_EXPORT GpuMemoryBuffer {
public:
- enum AccessMode {
- READ_ONLY,
- WRITE_ONLY,
- READ_WRITE,
- };
-
GpuMemoryBuffer();
virtual ~GpuMemoryBuffer();
- // Maps the buffer so the client can write the bitmap data in |*vaddr|
- // subsequently. This call may block, for instance if the hardware needs
- // to finish rendering or if CPU caches need to be synchronized.
- virtual void Map(AccessMode mode, void** vaddr) = 0;
+ // Maps the buffer into the client's address space so it can be written to by
+ // the CPU. This call may block, for instance if the GPU needs to finish
+ // accessing the buffer or if CPU caches need to be synchronized. Returns NULL
+ // on failure.
+ virtual void* Map() = 0;
- // Unmaps the buffer. Called after all changes to the buffer are
- // completed.
+ // Unmaps the buffer. It's illegal to use the pointer returned by Map() after
+ // this has been called.
virtual void Unmap() = 0;
// Returns true iff the buffer is mapped.
diff --git a/chromium/ui/gfx/gtk_compat.h b/chromium/ui/gfx/gtk_compat.h
deleted file mode 100644
index ca14a27627a..00000000000
--- a/chromium/ui/gfx/gtk_compat.h
+++ /dev/null
@@ -1,97 +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_GTK_COMPAT_H_
-#define UI_GFX_GTK_COMPAT_H_
-
-#include <gtk/gtk.h>
-
-// Google Chrome must depend on GTK 2.18, at least until the next LTS drops
-// (and we might have to extend which version of GTK we want to target due to
-// RHEL). To make our porting job for GTK3 easier, we define all the methods
-// that replace deprecated APIs in this file and then include it everywhere.
-//
-// This file is organized first by version, and then with each version,
-// alphabetically by method.
-//
-// For Google Chrome builds, we want to support RHEL 6, which uses GTK 2.18,
-// but the official builder is Ubuntu Lucid with GTK 2.20. Thus for Google
-// Chrome builds, we define the GTK 2.20.0 compatibility functions even though
-// the system GTK provides the functions.
-
-#if !GTK_CHECK_VERSION(2, 20, 0) || defined(GOOGLE_CHROME_BUILD)
-inline gboolean gtk_widget_get_mapped(GtkWidget* widget) {
- return GTK_WIDGET_MAPPED(widget);
-}
-
-inline gboolean gtk_widget_get_realized(GtkWidget* widget) {
- return GTK_WIDGET_REALIZED(widget);
-}
-
-inline gboolean gtk_widget_is_toplevel(GtkWidget* widget) {
- return GTK_WIDGET_TOPLEVEL(widget);
-}
-
-inline void gtk_widget_set_mapped(GtkWidget* widget,
- gboolean mapped) {
- if (mapped)
- GTK_WIDGET_SET_FLAGS(widget, GTK_MAPPED);
- else
- GTK_WIDGET_UNSET_FLAGS(widget, GTK_MAPPED);
-}
-
-inline void gtk_widget_set_realized(GtkWidget* widget,
- gboolean realized) {
- if (realized)
- GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
- else
- GTK_WIDGET_UNSET_FLAGS(widget, GTK_REALIZED);
-}
-
-inline void gtk_widget_style_attach(GtkWidget* widget) {
- widget->style = gtk_style_attach(widget->style, widget->window);
-}
-#endif // !GTK_CHECK_VERSION(2, 20, 0) || defined(GOOGLE_CHROME_BUILD)
-
-#if !GTK_CHECK_VERSION(2, 22, 0)
-inline GdkWindow* gdk_drag_context_get_source_window(GdkDragContext *context) {
- return context->source_window;
-}
-
-inline gint gdk_visual_get_depth(GdkVisual* visual) {
- return visual->depth;
-}
-
-inline GdkWindow* gtk_button_get_event_window(GtkButton* button) {
- return button->event_window;
-}
-#endif // !GTK_CHECK_VERSION(2, 22, 0)
-
-#if !GTK_CHECK_VERSION(2, 24, 0)
-inline void gdk_pixmap_get_size(GdkPixmap* pixmap, gint* width, gint* height) {
- gdk_drawable_get_size(GDK_DRAWABLE(pixmap), width, height);
-}
-
-inline GdkDisplay* gdk_window_get_display(GdkWindow* window) {
- return gdk_drawable_get_display(GDK_DRAWABLE(window));
-}
-
-inline int gdk_window_get_height(GdkWindow* window) {
- int height;
- gdk_drawable_get_size(GDK_DRAWABLE(window), NULL, &height);
- return height;
-}
-
-inline GdkScreen* gdk_window_get_screen(GdkWindow* window) {
- return gdk_drawable_get_screen(GDK_DRAWABLE(window));
-}
-
-inline int gdk_window_get_width(GdkWindow* window) {
- int width;
- gdk_drawable_get_size(GDK_DRAWABLE(window), &width, NULL);
- return width;
-}
-#endif // !GTK_CHECK_VERSION(2, 24, 0)
-
-#endif // UI_GFX_GTK_COMPAT_H_
diff --git a/chromium/ui/gfx/gtk_native_view_id_manager.cc b/chromium/ui/gfx/gtk_native_view_id_manager.cc
deleted file mode 100644
index 0844b190dd9..00000000000
--- a/chromium/ui/gfx/gtk_native_view_id_manager.cc
+++ /dev/null
@@ -1,254 +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 "ui/gfx/gtk_native_view_id_manager.h"
-
-#include <gdk/gdkx.h>
-#include <gtk/gtk.h>
-
-#include "base/logging.h"
-#include "base/memory/singleton.h"
-#include "base/rand_util.h"
-#include "ui/gfx/gdk_compat.h"
-#include "ui/gfx/gtk_compat.h"
-#include "ui/gfx/gtk_preserve_window.h"
-
-// -----------------------------------------------------------------------------
-// Bounce functions for GTK to callback into a C++ object...
-
-void OnRealize(gfx::NativeView widget, void* arg) {
- GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg);
- manager->OnRealize(widget);
-}
-
-void OnUnrealize(gfx::NativeView widget, void *arg) {
- GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg);
- manager->OnUnrealize(widget);
-}
-
-static void OnDestroy(GtkObject* obj, void* arg) {
- GtkNativeViewManager* manager = reinterpret_cast<GtkNativeViewManager*>(arg);
- manager->OnDestroy(reinterpret_cast<GtkWidget*>(obj));
-}
-
-// -----------------------------------------------------------------------------
-
-
-// -----------------------------------------------------------------------------
-// Public functions...
-
-GtkNativeViewManager::GtkNativeViewManager() {
-}
-
-GtkNativeViewManager::~GtkNativeViewManager() {
-}
-
-// static
-GtkNativeViewManager* GtkNativeViewManager::GetInstance() {
- return Singleton<GtkNativeViewManager>::get();
-}
-
-gfx::NativeViewId GtkNativeViewManager::GetIdForWidget(gfx::NativeView widget) {
- // This is just for unit tests:
- if (!widget)
- return 0;
-
- base::AutoLock locked(lock_);
-
- std::map<gfx::NativeView, gfx::NativeViewId>::const_iterator i =
- native_view_to_id_.find(widget);
-
- if (i != native_view_to_id_.end())
- return i->second;
-
- gfx::NativeViewId new_id =
- static_cast<gfx::NativeViewId>(base::RandUint64());
- while (id_to_info_.find(new_id) != id_to_info_.end())
- new_id = static_cast<gfx::NativeViewId>(base::RandUint64());
-
- NativeViewInfo info;
- info.widget = widget;
- if (gtk_widget_get_realized(widget)) {
- GdkWindow *gdk_window = gtk_widget_get_window(widget);
- DCHECK(gdk_window);
- info.x_window_id = GDK_WINDOW_XID(gdk_window);
- }
-
- native_view_to_id_[widget] = new_id;
- id_to_info_[new_id] = info;
-
- g_signal_connect(widget, "realize", G_CALLBACK(::OnRealize), this);
- g_signal_connect(widget, "unrealize", G_CALLBACK(::OnUnrealize), this);
- g_signal_connect(widget, "destroy", G_CALLBACK(::OnDestroy), this);
-
- return new_id;
-}
-
-bool GtkNativeViewManager::GetXIDForId(XID* output, gfx::NativeViewId id) {
- base::AutoLock locked(lock_);
-
- std::map<gfx::NativeViewId, NativeViewInfo>::const_iterator i =
- id_to_info_.find(id);
-
- if (i == id_to_info_.end())
- return false;
-
- *output = i->second.x_window_id;
- return true;
-}
-
-bool GtkNativeViewManager::GetNativeViewForId(gfx::NativeView* output,
- gfx::NativeViewId id) {
- base::AutoLock locked(lock_);
-
- std::map<gfx::NativeViewId, NativeViewInfo>::const_iterator i =
- id_to_info_.find(id);
-
- if (i == id_to_info_.end())
- return false;
-
- *output = i->second.widget;
- return true;
-}
-
-bool GtkNativeViewManager::GetPermanentXIDForId(XID* output,
- gfx::NativeViewId id) {
- base::AutoLock locked(lock_);
-
- std::map<gfx::NativeViewId, NativeViewInfo>::iterator i =
- id_to_info_.find(id);
-
- if (i == id_to_info_.end())
- return false;
-
- // We only return permanent XIDs for widgets that allow us to guarantee that
- // the XID will not change.
- DCHECK(GTK_IS_PRESERVE_WINDOW(i->second.widget));
- GtkPreserveWindow* widget =
- reinterpret_cast<GtkPreserveWindow*>(i->second.widget);
- gtk_preserve_window_set_preserve(widget, TRUE);
-
- *output = GDK_WINDOW_XID(gtk_widget_get_window(i->second.widget));
-
- // Update the reference count on the permanent XID.
- PermanentXIDInfo info;
- info.widget = widget;
- info.ref_count = 1;
- std::pair<std::map<XID, PermanentXIDInfo>::iterator, bool> ret =
- perm_xid_to_info_.insert(std::make_pair(*output, info));
-
- if (!ret.second) {
- DCHECK(ret.first->second.widget == widget);
- ret.first->second.ref_count++;
- }
-
- return true;
-}
-
-bool GtkNativeViewManager::AddRefPermanentXID(XID xid) {
- base::AutoLock locked(lock_);
-
- std::map<XID, PermanentXIDInfo>::iterator i =
- perm_xid_to_info_.find(xid);
-
- if (i == perm_xid_to_info_.end())
- return false;
-
- i->second.ref_count++;
-
- return true;
-}
-
-void GtkNativeViewManager::ReleasePermanentXID(XID xid) {
- base::AutoLock locked(lock_);
-
- std::map<XID, PermanentXIDInfo>::iterator i =
- perm_xid_to_info_.find(xid);
-
- if (i == perm_xid_to_info_.end())
- return;
-
- if (i->second.ref_count > 1) {
- i->second.ref_count--;
- } else {
- if (i->second.widget) {
- gtk_preserve_window_set_preserve(i->second.widget, FALSE);
- } else {
- GdkWindow* window = reinterpret_cast<GdkWindow*>(
- gdk_x11_window_lookup_for_display(gdk_display_get_default(), xid));
- DCHECK(window);
- gdk_window_destroy(window);
- }
- perm_xid_to_info_.erase(i);
- }
-}
-
-// -----------------------------------------------------------------------------
-
-
-// -----------------------------------------------------------------------------
-// Private functions...
-
-gfx::NativeViewId GtkNativeViewManager::GetWidgetId(gfx::NativeView widget) {
- lock_.AssertAcquired();
-
- std::map<gfx::NativeView, gfx::NativeViewId>::const_iterator i =
- native_view_to_id_.find(widget);
-
- CHECK(i != native_view_to_id_.end());
- return i->second;
-}
-
-void GtkNativeViewManager::OnRealize(gfx::NativeView widget) {
- base::AutoLock locked(lock_);
-
- const gfx::NativeViewId id = GetWidgetId(widget);
- std::map<gfx::NativeViewId, NativeViewInfo>::iterator i =
- id_to_info_.find(id);
-
- CHECK(i != id_to_info_.end());
-
- GdkWindow* gdk_window = gtk_widget_get_window(widget);
- CHECK(gdk_window);
- i->second.x_window_id = GDK_WINDOW_XID(gdk_window);
-}
-
-void GtkNativeViewManager::OnUnrealize(gfx::NativeView widget) {
- base::AutoLock locked(lock_);
-
- const gfx::NativeViewId id = GetWidgetId(widget);
- std::map<gfx::NativeViewId, NativeViewInfo>::iterator i =
- id_to_info_.find(id);
-
- CHECK(i != id_to_info_.end());
-}
-
-void GtkNativeViewManager::OnDestroy(gfx::NativeView widget) {
- base::AutoLock locked(lock_);
-
- std::map<gfx::NativeView, gfx::NativeViewId>::iterator i =
- native_view_to_id_.find(widget);
- CHECK(i != native_view_to_id_.end());
-
- std::map<gfx::NativeViewId, NativeViewInfo>::iterator j =
- id_to_info_.find(i->second);
- CHECK(j != id_to_info_.end());
-
- // If the XID is supposed to outlive the widget, mark it
- // in the lookup table.
- if (GTK_IS_PRESERVE_WINDOW(widget) &&
- gtk_preserve_window_get_preserve(
- reinterpret_cast<GtkPreserveWindow*>(widget))) {
- std::map<XID, PermanentXIDInfo>::iterator k =
- perm_xid_to_info_.find(GDK_WINDOW_XID(gtk_widget_get_window(widget)));
-
- if (k != perm_xid_to_info_.end())
- k->second.widget = NULL;
- }
-
- native_view_to_id_.erase(i);
- id_to_info_.erase(j);
-}
-
-// -----------------------------------------------------------------------------
diff --git a/chromium/ui/gfx/gtk_native_view_id_manager.h b/chromium/ui/gfx/gtk_native_view_id_manager.h
deleted file mode 100644
index 44219209273..00000000000
--- a/chromium/ui/gfx/gtk_native_view_id_manager.h
+++ /dev/null
@@ -1,138 +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_GTK_NATIVE_VIEW_ID_MANAGER_H_
-#define UI_GFX_GTK_NATIVE_VIEW_ID_MANAGER_H_
-
-#include <map>
-
-#include "base/synchronization/lock.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/native_widget_types.h"
-
-template <typename T> struct DefaultSingletonTraits;
-
-typedef unsigned long XID;
-struct _GtkPreserveWindow;
-
-// NativeViewIds are the opaque values which the renderer holds as a reference
-// to a window.
-//
-// We could make NativeViewIds be the X id of the window. However, at the
-// time when we need to tell the renderer about its NativeViewId, an XID isn't
-// availible and it goes very much against the grain of the code to make it so.
-// Also, we worry that GTK might choose to change the underlying X window id
-// when, say, the widget is hidden or repacked. Finally, if we used XIDs then a
-// compromised renderer could start asking questions about any X windows on the
-// system.
-//
-// Thus, we have this object. It produces random NativeViewIds from GtkWidget
-// pointers and observes the various signals from the widget for when an X
-// window is created, destroyed etc. Thus it provides a thread safe mapping
-// from NativeViewIds to the current XID for that widget.
-class GFX_EXPORT GtkNativeViewManager {
- public:
- // Returns the singleton instance.
- static GtkNativeViewManager* GetInstance();
-
- // Must be called from the UI thread:
- //
- // Return a NativeViewId for the given widget and attach to the various
- // signals emitted by that widget. The NativeViewId is pseudo-randomly
- // allocated so that a compromised renderer trying to guess values will fail
- // with high probability. The NativeViewId will not be reused for the
- // lifetime of the GtkWidget.
- gfx::NativeViewId GetIdForWidget(gfx::NativeView widget);
-
- // May be called from any thread:
- //
- // xid: (output) the resulting X window ID, or 0
- // id: a value previously returned from GetIdForWidget
- // returns: true if |id| is a valid id, false otherwise.
- //
- // If the widget referenced by |id| does not current have an X window id,
- // |*xid| is set to 0.
- bool GetXIDForId(XID* xid, gfx::NativeViewId id);
-
- // May be called from the UI thread:
- //
- // Same as GetXIDForId except it returns the NativeView (GtkWidget*).
- bool GetNativeViewForId(gfx::NativeView* xid, gfx::NativeViewId id);
-
- // Must be called from the UI thread because we may need the associated
- // widget to create a window.
- //
- // Keeping the XID permanent requires a bit of overhead, so it must
- // be explicitly requested.
- //
- // xid: (output) the resulting X window
- // id: a value previously returned from GetIdForWidget
- // returns: true if |id| is a valid id, false otherwise.
- bool GetPermanentXIDForId(XID* xid, gfx::NativeViewId id);
-
- // Can be called from any thread.
- // Will return false if the given XID isn't permanent or has already been
- // released.
- bool AddRefPermanentXID(XID xid);
-
- // Must be called from the UI thread because we may need to access a
- // GtkWidget or destroy a GdkWindow.
- //
- // If the widget associated with the XID is still alive, allow the widget
- // to destroy the associated XID when it wants. Otherwise, destroy the
- // GdkWindow associated with the XID.
- void ReleasePermanentXID(XID xid);
-
- // These are actually private functions, but need to be called from statics.
- void OnRealize(gfx::NativeView widget);
- void OnUnrealize(gfx::NativeView widget);
- void OnDestroy(gfx::NativeView widget);
-
- private:
- // This object is a singleton:
- GtkNativeViewManager();
- ~GtkNativeViewManager();
- friend struct DefaultSingletonTraits<GtkNativeViewManager>;
-
- struct NativeViewInfo {
- NativeViewInfo() : widget(NULL), x_window_id(0) {
- }
- gfx::NativeView widget;
- XID x_window_id;
- };
-
- gfx::NativeViewId GetWidgetId(gfx::NativeView id);
-
- // protects native_view_to_id_ and id_to_info_
- base::Lock lock_;
-
- // If asked for an id for the same widget twice, we want to return the same
- // id. So this records the current mapping.
- std::map<gfx::NativeView, gfx::NativeViewId> native_view_to_id_;
- std::map<gfx::NativeViewId, NativeViewInfo> id_to_info_;
-
- struct PermanentXIDInfo {
- PermanentXIDInfo() : widget(NULL), ref_count(0) {
- }
- _GtkPreserveWindow* widget;
- int ref_count;
- };
-
- // Used to maintain the reference count for permanent XIDs
- // (referenced by GetPermanentXIDForId and dereferenced by
- // ReleasePermanentXID). Only those XIDs with a positive reference count
- // will be in the table.
- //
- // In general, several GTK widgets may share the same X window. We assume
- // that is not true of the widgets stored in this registry.
- //
- // An XID will map to NULL, if there is an outstanding reference but the
- // widget was destroyed. In this case, the destruction of the X window
- // is deferred to the dropping of all references.
- std::map<XID, PermanentXIDInfo> perm_xid_to_info_;
-
- DISALLOW_COPY_AND_ASSIGN(GtkNativeViewManager);
-};
-
-#endif // UI_GFX_GTK_NATIVE_VIEW_ID_MANAGER_H_
diff --git a/chromium/ui/gfx/gtk_preserve_window.cc b/chromium/ui/gfx/gtk_preserve_window.cc
deleted file mode 100644
index 78a49c28510..00000000000
--- a/chromium/ui/gfx/gtk_preserve_window.cc
+++ /dev/null
@@ -1,264 +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 "ui/gfx/gtk_preserve_window.h"
-
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
-
-#include "ui/gfx/gtk_compat.h"
-
-G_BEGIN_DECLS
-
-#define GTK_PRESERVE_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
- GTK_TYPE_PRESERVE_WINDOW, \
- GtkPreserveWindowPrivate))
-
-typedef struct _GtkPreserveWindowPrivate GtkPreserveWindowPrivate;
-
-struct _GtkPreserveWindowPrivate {
- // If true, don't create/destroy windows on realize/unrealize.
- gboolean preserve_window;
-
- // Whether or not we delegate the resize of the GdkWindow
- // to someone else.
- gboolean delegate_resize;
-
- // Accessible factory and userdata.
- AtkObject* (*accessible_factory)(void* userdata);
- void* accessible_factory_userdata;
-};
-
-G_DEFINE_TYPE(GtkPreserveWindow, gtk_preserve_window, GTK_TYPE_FIXED)
-
-static void gtk_preserve_window_destroy(GtkObject* object);
-static void gtk_preserve_window_realize(GtkWidget* widget);
-static void gtk_preserve_window_unrealize(GtkWidget* widget);
-static void gtk_preserve_window_size_allocate(GtkWidget* widget,
- GtkAllocation* allocation);
-static AtkObject* gtk_preserve_window_get_accessible(GtkWidget* widget);
-
-static void gtk_preserve_window_class_init(GtkPreserveWindowClass *klass) {
- GtkWidgetClass* widget_class = reinterpret_cast<GtkWidgetClass*>(klass);
- widget_class->realize = gtk_preserve_window_realize;
- widget_class->unrealize = gtk_preserve_window_unrealize;
- widget_class->size_allocate = gtk_preserve_window_size_allocate;
- widget_class->get_accessible = gtk_preserve_window_get_accessible;
-
- GtkObjectClass* object_class = reinterpret_cast<GtkObjectClass*>(klass);
- object_class->destroy = gtk_preserve_window_destroy;
-
- GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
- g_type_class_add_private(gobject_class, sizeof(GtkPreserveWindowPrivate));
-}
-
-static void gtk_preserve_window_init(GtkPreserveWindow* widget) {
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
- priv->preserve_window = FALSE;
- priv->accessible_factory = NULL;
- priv->accessible_factory_userdata = NULL;
-
- // These widgets always have their own window.
- gtk_widget_set_has_window(GTK_WIDGET(widget), TRUE);
-}
-
-GtkWidget* gtk_preserve_window_new() {
- return GTK_WIDGET(g_object_new(GTK_TYPE_PRESERVE_WINDOW, NULL));
-}
-
-static void gtk_preserve_window_destroy(GtkObject* object) {
- GtkWidget* widget = reinterpret_cast<GtkWidget*>(object);
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
-
- GdkWindow* gdk_window = gtk_widget_get_window(widget);
- if (gdk_window) {
- gdk_window_set_user_data(gdk_window, NULL);
- // If the window is preserved, someone else must destroy it.
- if (!priv->preserve_window)
- gdk_window_destroy(gdk_window);
- gtk_widget_set_window(widget, NULL);
- }
-
- GTK_OBJECT_CLASS(gtk_preserve_window_parent_class)->destroy(object);
-}
-
-static void gtk_preserve_window_realize(GtkWidget* widget) {
- g_return_if_fail(GTK_IS_PRESERVE_WINDOW(widget));
-
- GdkWindow* gdk_window = gtk_widget_get_window(widget);
- if (gdk_window) {
- GtkAllocation allocation;
- gtk_widget_get_allocation(widget, &allocation);
-
- gdk_window_reparent(gdk_window,
- gtk_widget_get_parent_window(widget),
- allocation.x,
- allocation.y);
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
- if (!priv->delegate_resize) {
- gdk_window_resize(gdk_window,
- allocation.width,
- allocation.height);
- }
- gint event_mask = gtk_widget_get_events(widget);
- event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK;
- gdk_window_set_events(gdk_window, (GdkEventMask) event_mask);
- gdk_window_set_user_data(gdk_window, widget);
-
- gtk_widget_set_realized(widget, TRUE);
-
- gtk_widget_style_attach(widget);
- gtk_style_set_background(gtk_widget_get_style(widget),
- gdk_window, GTK_STATE_NORMAL);
- } else {
- GTK_WIDGET_CLASS(gtk_preserve_window_parent_class)->realize(widget);
- }
-}
-
-static void gtk_preserve_window_unrealize(GtkWidget* widget) {
- g_return_if_fail(GTK_IS_PRESERVE_WINDOW(widget));
-
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
- if (priv->preserve_window) {
- GtkWidgetClass* widget_class =
- GTK_WIDGET_CLASS(gtk_preserve_window_parent_class);
- GtkContainerClass* container_class =
- GTK_CONTAINER_CLASS(gtk_preserve_window_parent_class);
-
- if (gtk_widget_get_mapped(widget)) {
- widget_class->unmap(widget);
-
- gtk_widget_set_mapped(widget, FALSE);
- }
-
- // This is the behavior from GtkWidget, inherited by GtkFixed.
- // It is unclear why we should not call the potentially overridden
- // unrealize method (via the callback), but doing so causes errors.
- container_class->forall(
- GTK_CONTAINER(widget), FALSE,
- reinterpret_cast<GtkCallback>(gtk_widget_unrealize), NULL);
-
- GdkWindow* gdk_window = gtk_widget_get_window(widget);
-
- // TODO(erg): Almost all style handling will need to be overhauled in GTK3.
- gtk_style_detach(gtk_widget_get_style(widget));
- gdk_window_reparent(gdk_window, gdk_get_default_root_window(), 0, 0);
- gtk_selection_remove_all(widget);
- gdk_window_set_user_data(gdk_window, NULL);
-
- gtk_widget_set_realized(widget, FALSE);
- } else {
- GTK_WIDGET_CLASS(gtk_preserve_window_parent_class)->unrealize(widget);
- }
-}
-
-gboolean gtk_preserve_window_get_preserve(GtkPreserveWindow* window) {
- g_return_val_if_fail(GTK_IS_PRESERVE_WINDOW(window), FALSE);
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(window);
-
- return priv->preserve_window;
-}
-
-void gtk_preserve_window_set_preserve(GtkPreserveWindow* window,
- gboolean value) {
- g_return_if_fail(GTK_IS_PRESERVE_WINDOW(window));
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(window);
- priv->preserve_window = value;
-
- GtkWidget* widget = GTK_WIDGET(window);
- GdkWindow* gdk_window = gtk_widget_get_window(widget);
- if (value && !gdk_window) {
- GdkWindowAttr attributes;
- gint attributes_mask;
-
- // We may not know the width and height, so we rely on the fact
- // that a size-allocation will resize it later.
- attributes.width = 1;
- attributes.height = 1;
-
- attributes.window_type = GDK_WINDOW_CHILD;
- attributes.wclass = GDK_INPUT_OUTPUT;
- attributes.override_redirect = TRUE;
-
- attributes.visual = gtk_widget_get_visual(widget);
- attributes.colormap = gtk_widget_get_colormap(widget);
-
- attributes.event_mask = gtk_widget_get_events(widget);
- attributes.event_mask |= GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK;
-
- attributes_mask = GDK_WA_VISUAL | GDK_WA_COLORMAP | GDK_WA_NOREDIR;
- gdk_window = gdk_window_new(
- gdk_get_default_root_window(), &attributes, attributes_mask);
- gtk_widget_set_window(widget, gdk_window);
- } else if (!value && gdk_window && !gtk_widget_get_realized(widget)) {
- gdk_window_destroy(gdk_window);
- gtk_widget_set_window(widget, NULL);
- }
-}
-
-void gtk_preserve_window_size_allocate(GtkWidget* widget,
- GtkAllocation* allocation) {
- g_return_if_fail(GTK_IS_PRESERVE_WINDOW(widget));
-
- gtk_widget_set_allocation(widget, allocation);
-
- if (gtk_widget_get_realized(widget)) {
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
- GdkWindow* gdk_window = gtk_widget_get_window(widget);
- if (priv->delegate_resize) {
- gdk_window_move(gdk_window, allocation->x, allocation->y);
- } else {
- gdk_window_move_resize(
- gdk_window, allocation->x, allocation->y,
- allocation->width, allocation->height);
- }
- }
-
- // Propagate resize to children
- guint16 border_width = gtk_container_get_border_width(GTK_CONTAINER(widget));
- GList *children = GTK_FIXED(widget)->children;
- while (children) {
- GtkFixedChild *child = reinterpret_cast<GtkFixedChild*>(children->data);
- if (gtk_widget_get_visible(child->widget)) {
- GtkRequisition child_requisition;
- gtk_widget_get_child_requisition(child->widget, &child_requisition);
-
- GtkAllocation child_allocation;
- child_allocation.x = child->x + border_width;
- child_allocation.y = child->y + border_width;
- child_allocation.width = child_requisition.width;
- child_allocation.height = child_requisition.height;
-
- gtk_widget_size_allocate(child->widget, &child_allocation);
- }
- children = children->next;
- }
-}
-
-void gtk_preserve_window_delegate_resize(GtkPreserveWindow* widget,
- gboolean delegate) {
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
- priv->delegate_resize = delegate;
-}
-
-void gtk_preserve_window_set_accessible_factory(
- GtkPreserveWindow* widget,
- AtkObject* (*factory)(void* userdata),
- gpointer userdata) {
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
- priv->accessible_factory = factory;
- priv->accessible_factory_userdata = userdata;
-}
-
-AtkObject* gtk_preserve_window_get_accessible(GtkWidget* widget) {
- GtkPreserveWindowPrivate* priv = GTK_PRESERVE_WINDOW_GET_PRIVATE(widget);
- if (priv->accessible_factory) {
- return priv->accessible_factory(priv->accessible_factory_userdata);
- } else {
- return GTK_WIDGET_CLASS(gtk_preserve_window_parent_class)
- ->get_accessible(widget);
- }
-}
-
-G_END_DECLS
diff --git a/chromium/ui/gfx/gtk_preserve_window.h b/chromium/ui/gfx/gtk_preserve_window.h
deleted file mode 100644
index 5b5198bf56f..00000000000
--- a/chromium/ui/gfx/gtk_preserve_window.h
+++ /dev/null
@@ -1,74 +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_GTK_PRESERVE_WINDOW_H_
-#define UI_GFX_GTK_PRESERVE_WINDOW_H_
-
-#include <atk/atk.h>
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
-
-#include "ui/gfx/gfx_export.h"
-
-// GtkFixed creates an X window when realized and destroys an X window
-// when unrealized. GtkPreserveWindow allows overrides this
-// behaviour. When preserve is set (via gtk_preserve_window_set_preserve),
-// the X window is only destroyed when the widget is destroyed.
-
-G_BEGIN_DECLS
-
-#define GTK_TYPE_PRESERVE_WINDOW \
- (gtk_preserve_window_get_type())
-#define GTK_PRESERVE_WINDOW(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_PRESERVE_WINDOW, \
- GtkPreserveWindow))
-#define GTK_PRESERVE_WINDOW_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_PRESERVE_WINDOW, \
- GtkPreserveWindowClass))
-#define GTK_IS_PRESERVE_WINDOW(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_PRESERVE_WINDOW))
-#define GTK_IS_PRESERVE_WINDOW_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_PRESERVE_WINDOW))
-#define GTK_PRESERVE_WINDOW_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS((obj), GTK_TYPE_PRESERVE_WINDOW, \
- GtkPreserveWindowClass))
-
-typedef struct _GtkPreserveWindow GtkPreserveWindow;
-typedef struct _GtkPreserveWindowClass GtkPreserveWindowClass;
-
-struct _GtkPreserveWindow {
- // Parent class.
- GtkFixed fixed;
-};
-
-struct _GtkPreserveWindowClass {
- GtkFixedClass parent_class;
-};
-
-GFX_EXPORT GType gtk_preserve_window_get_type() G_GNUC_CONST;
-GFX_EXPORT GtkWidget* gtk_preserve_window_new();
-
-// Whether or not we should preserve associated windows as the widget
-// is realized or unrealized.
-GFX_EXPORT gboolean gtk_preserve_window_get_preserve(GtkPreserveWindow* widget);
-GFX_EXPORT void gtk_preserve_window_set_preserve(GtkPreserveWindow* widget,
- gboolean value);
-
-// Whether or not someone else will gdk_window_resize the GdkWindow associated
-// with this widget (needed by the GPU process to synchronize resizing
-// with swapped between front and back buffer).
-GFX_EXPORT void gtk_preserve_window_delegate_resize(GtkPreserveWindow* widget,
- gboolean delegate);
-
-// Provide a function to return an AtkObject* when calls to get_accessible
-// are made on this widget. The parameter |userdata| will be passed to the
-// factory function.
-GFX_EXPORT void gtk_preserve_window_set_accessible_factory(
- GtkPreserveWindow* widget,
- AtkObject* (*factory)(void* userdata),
- gpointer userdata);
-
-G_END_DECLS
-
-#endif // UI_GFX_GTK_PRESERVE_WINDOW_H_
diff --git a/chromium/ui/gfx/gtk_util.cc b/chromium/ui/gfx/gtk_util.cc
deleted file mode 100644
index 0c111687572..00000000000
--- a/chromium/ui/gfx/gtk_util.cc
+++ /dev/null
@@ -1,190 +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 "ui/gfx/gtk_util.h"
-
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
-#include <stdlib.h>
-
-#include "base/basictypes.h"
-#include "base/command_line.h"
-#include "base/memory/scoped_ptr.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkUnPreMultiply.h"
-#include "ui/gfx/rect.h"
-
-namespace {
-
-// A process wide singleton that manages our usage of gdk cursors.
-// gdk_cursor_new() hits the disk in several places and GdkCursor instances can
-// be reused throughout the process.
-class GdkCursorCache {
- public:
- GdkCursorCache() {}
- ~GdkCursorCache() {
- for (GdkCursorMap::iterator i(cursors_.begin()); i != cursors_.end(); ++i) {
- gdk_cursor_unref(i->second);
- }
- cursors_.clear();
- }
-
- GdkCursor* GetCursorImpl(GdkCursorType type) {
- GdkCursorMap::iterator it = cursors_.find(type);
- GdkCursor* cursor = NULL;
- if (it == cursors_.end()) {
- cursor = gdk_cursor_new(type);
- cursors_.insert(std::make_pair(type, cursor));
- } else {
- cursor = it->second;
- }
-
- // It is not necessary to add a reference here. The callers can ref the
- // cursor if they need it for something.
- return cursor;
- }
-
- private:
- typedef std::map<GdkCursorType, GdkCursor*> GdkCursorMap;
- GdkCursorMap cursors_;
-
- DISALLOW_COPY_AND_ASSIGN(GdkCursorCache);
-};
-
-} // namespace
-
-namespace gfx {
-
-static void CommonInitFromCommandLine(const CommandLine& command_line,
- void (*init_func)(gint*, gchar***)) {
- const std::vector<std::string>& args = command_line.argv();
- int argc = args.size();
- scoped_ptr<char *[]> argv(new char *[argc + 1]);
- for (size_t i = 0; i < args.size(); ++i) {
- // TODO(piman@google.com): can gtk_init modify argv? Just being safe
- // here.
- argv[i] = strdup(args[i].c_str());
- }
- argv[argc] = NULL;
- char **argv_pointer = argv.get();
-
- init_func(&argc, &argv_pointer);
- for (size_t i = 0; i < args.size(); ++i) {
- free(argv[i]);
- }
-}
-
-void GtkInitFromCommandLine(const CommandLine& command_line) {
- CommonInitFromCommandLine(command_line, gtk_init);
-}
-
-void GdkInitFromCommandLine(const CommandLine& command_line) {
- CommonInitFromCommandLine(command_line, gdk_init);
-}
-
-GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap) {
- if (bitmap.isNull())
- return NULL;
-
- SkAutoLockPixels lock_pixels(bitmap);
-
- int width = bitmap.width();
- int height = bitmap.height();
-
- GdkPixbuf* pixbuf = gdk_pixbuf_new(
- GDK_COLORSPACE_RGB, // The only colorspace gtk supports.
- TRUE, // There is an alpha channel.
- 8,
- width, height);
-
- // SkBitmaps are premultiplied, we need to unpremultiply them.
- const int kBytesPerPixel = 4;
- uint8* divided = gdk_pixbuf_get_pixels(pixbuf);
-
- for (int y = 0, i = 0; y < height; y++) {
- for (int x = 0; x < width; x++) {
- uint32 pixel = bitmap.getAddr32(0, y)[x];
-
- int alpha = SkColorGetA(pixel);
- if (alpha != 0 && alpha != 255) {
- SkColor unmultiplied = SkUnPreMultiply::PMColorToColor(pixel);
- divided[i + 0] = SkColorGetR(unmultiplied);
- divided[i + 1] = SkColorGetG(unmultiplied);
- divided[i + 2] = SkColorGetB(unmultiplied);
- divided[i + 3] = alpha;
- } else {
- divided[i + 0] = SkColorGetR(pixel);
- divided[i + 1] = SkColorGetG(pixel);
- divided[i + 2] = SkColorGetB(pixel);
- divided[i + 3] = alpha;
- }
- i += kBytesPerPixel;
- }
- }
-
- return pixbuf;
-}
-
-void SubtractRectanglesFromRegion(GdkRegion* region,
- const std::vector<Rect>& cutouts) {
- for (size_t i = 0; i < cutouts.size(); ++i) {
- GdkRectangle rect = cutouts[i].ToGdkRectangle();
- GdkRegion* rect_region = gdk_region_rectangle(&rect);
- gdk_region_subtract(region, rect_region);
- // TODO(deanm): It would be nice to be able to reuse the GdkRegion here.
- gdk_region_destroy(rect_region);
- }
-}
-
-GdkCursor* GetCursor(int type) {
- CR_DEFINE_STATIC_LOCAL(GdkCursorCache, impl, ());
- return impl.GetCursorImpl(static_cast<GdkCursorType>(type));
-}
-
-void InitRCStyles() {
- static const char kRCText[] =
- // Make our dialogs styled like the GNOME HIG.
- //
- // TODO(evanm): content-area-spacing was introduced in a later
- // version of GTK, so we need to set that manually on all dialogs.
- // Perhaps it would make sense to have a shared FixupDialog() function.
- "style \"gnome-dialog\" {\n"
- " xthickness = 12\n"
- " GtkDialog::action-area-border = 0\n"
- " GtkDialog::button-spacing = 6\n"
- " GtkDialog::content-area-spacing = 18\n"
- " GtkDialog::content-area-border = 12\n"
- "}\n"
- // Note we set it at the "application" priority, so users can override.
- "widget \"GtkDialog\" style : application \"gnome-dialog\"\n"
-
- // Make our about dialog special, so the image is flush with the edge.
- "style \"about-dialog\" {\n"
- " GtkDialog::action-area-border = 12\n"
- " GtkDialog::button-spacing = 6\n"
- " GtkDialog::content-area-spacing = 18\n"
- " GtkDialog::content-area-border = 0\n"
- "}\n"
- "widget \"about-dialog\" style : application \"about-dialog\"\n";
-
- gtk_rc_parse_string(kRCText);
-}
-
-base::TimeDelta GetCursorBlinkCycle() {
- // From http://library.gnome.org/devel/gtk/unstable/GtkSettings.html, this is
- // the default value for gtk-cursor-blink-time.
- static const gint kGtkDefaultCursorBlinkTime = 1200;
-
- gint cursor_blink_time = kGtkDefaultCursorBlinkTime;
- gboolean cursor_blink = TRUE;
- g_object_get(gtk_settings_get_default(),
- "gtk-cursor-blink-time", &cursor_blink_time,
- "gtk-cursor-blink", &cursor_blink,
- NULL);
- return cursor_blink ?
- base::TimeDelta::FromMilliseconds(cursor_blink_time) :
- base::TimeDelta();
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/gtk_util.h b/chromium/ui/gfx/gtk_util.h
deleted file mode 100644
index 91f864bbe4c..00000000000
--- a/chromium/ui/gfx/gtk_util.h
+++ /dev/null
@@ -1,52 +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_GTK_UTIL_H_
-#define UI_GFX_GTK_UTIL_H_
-
-#include <vector>
-
-#include "base/time/time.h"
-#include "ui/gfx/gfx_export.h"
-
-typedef struct _GdkPixbuf GdkPixbuf;
-typedef struct _GdkRegion GdkRegion;
-typedef struct _GdkCursor GdkCursor;
-
-class CommandLine;
-class SkBitmap;
-
-namespace gfx {
-
-class Rect;
-
-// Call gtk_init() / gdk_init() using the argc and argv from command_line.
-// These init functions want an argc and argv that they can mutate; we provide
-// those, but leave the original CommandLine unaltered.
-GFX_EXPORT void GtkInitFromCommandLine(const CommandLine& command_line);
-GFX_EXPORT void GdkInitFromCommandLine(const CommandLine& command_line);
-
-// Convert and copy a SkBitmap to a GdkPixbuf. NOTE: this uses BGRAToRGBA, so
-// it is an expensive operation. The returned GdkPixbuf will have a refcount of
-// 1, and the caller is responsible for unrefing it when done.
-GFX_EXPORT GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap);
-
-// Modify the given region by subtracting the given rectangles.
-GFX_EXPORT void SubtractRectanglesFromRegion(GdkRegion* region,
- const std::vector<Rect>& cutouts);
-
-// Returns a static instance of a GdkCursor* object, sharable across the
-// process. Caller must gdk_cursor_ref() it if they want to assume ownership.
-GFX_EXPORT GdkCursor* GetCursor(int type);
-
-// Initialize some GTK settings so that our dialogs are consistent.
-GFX_EXPORT void InitRCStyles();
-
-// Queries GtkSettings for the cursor blink cycle time. Returns a 0 duration if
-// blinking is disabled.
-GFX_EXPORT base::TimeDelta GetCursorBlinkCycle();
-
-} // namespace gfx
-
-#endif // UI_GFX_GTK_UTIL_H_
diff --git a/chromium/ui/gfx/icon_util.cc b/chromium/ui/gfx/icon_util.cc
index 223618601e3..dd2b9bd6b50 100644
--- a/chromium/ui/gfx/icon_util.cc
+++ b/chromium/ui/gfx/icon_util.cc
@@ -77,7 +77,7 @@ bool BuildResizedImageFamily(const gfx::ImageFamily& image_family,
SkBitmap best_bitmap = best->AsBitmap();
// Only kARGB_8888 images are supported.
// This will also filter out images with no pixels.
- if (best_bitmap.config() != SkBitmap::kARGB_8888_Config)
+ if (best_bitmap.colorType() != kPMColor_SkColorType)
return false;
SkBitmap resized_bitmap = skia::ImageOperations::Resize(
best_bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
@@ -119,7 +119,7 @@ bool ConvertImageFamilyToBitmaps(
// Only 32 bit ARGB bitmaps are supported. We also make sure the bitmap has
// been properly initialized.
SkAutoLockPixels bitmap_lock(bitmap);
- if ((bitmap.config() != SkBitmap::kARGB_8888_Config) ||
+ if ((bitmap.colorType() != kPMColor_SkColorType) ||
(bitmap.getPixels() == NULL)) {
return false;
}
@@ -166,7 +166,7 @@ HICON 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.
SkAutoLockPixels bitmap_lock(bitmap);
- if ((bitmap.config() != SkBitmap::kARGB_8888_Config) ||
+ if ((bitmap.colorType() != kPMColor_SkColorType) ||
(bitmap.width() <= 0) || (bitmap.height() <= 0) ||
(bitmap.getPixels() == NULL))
return NULL;
@@ -177,13 +177,18 @@ HICON IconUtil::CreateHICONFromSkBitmap(const SkBitmap& bitmap) {
// alpha mask for the DIB.
BITMAPV5HEADER bitmap_header;
InitializeBitmapHeader(&bitmap_header, bitmap.width(), bitmap.height());
- void* bits;
- HDC hdc = ::GetDC(NULL);
+
+ void* bits = NULL;
HBITMAP dib;
- dib = ::CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&bitmap_header),
- DIB_RGB_COLORS, &bits, NULL, 0);
- DCHECK(dib);
- ::ReleaseDC(NULL, hdc);
+
+ {
+ base::win::ScopedGetDC hdc(NULL);
+ dib = ::CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&bitmap_header),
+ DIB_RGB_COLORS, &bits, NULL, 0);
+ }
+ if (!dib || !bits)
+ return NULL;
+
memcpy(bits, bitmap.getPixels(), bitmap.width() * bitmap.height() * 4);
// Icons are generally created using an AND and XOR masks where the AND
@@ -290,9 +295,8 @@ scoped_ptr<SkBitmap> IconUtil::CreateSkBitmapFromIconResource(HMODULE module,
DCHECK(png_data);
DCHECK_EQ(png_size, large_icon_entry->dwBytesInRes);
- const unsigned char* png_bytes =
- reinterpret_cast<const unsigned char*>(png_data);
- gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(png_bytes, png_size);
+ gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(
+ new base::RefCountedStaticMemory(png_data, png_size));
return scoped_ptr<SkBitmap>(new SkBitmap(image.AsBitmap()));
}
@@ -372,8 +376,7 @@ SkBitmap IconUtil::CreateSkBitmapFromHICONHelper(HICON icon,
// Allocating memory for the SkBitmap object. We are going to create an ARGB
// bitmap so we should set the configuration appropriately.
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, s.width(), s.height());
- bitmap.allocPixels();
+ bitmap.allocN32Pixels(s.width(), s.height());
bitmap.eraseARGB(0, 0, 0, 0);
SkAutoLockPixels bitmap_lock(bitmap);
diff --git a/chromium/ui/gfx/icon_util_unittest.cc b/chromium/ui/gfx/icon_util_unittest.cc
index 641422a24ef..1e2e96297c2 100644
--- a/chromium/ui/gfx/icon_util_unittest.cc
+++ b/chromium/ui/gfx/icon_util_unittest.cc
@@ -2,6 +2,8 @@
// 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/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
@@ -9,11 +11,10 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/gfx_paths.h"
-#include "ui/gfx/icon_util.h"
+#include "ui/gfx/icon_util_unittests_resource.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_family.h"
#include "ui/gfx/size.h"
-#include "ui/test/ui_unittests_resource.h"
namespace {
@@ -50,9 +51,8 @@ class IconUtilTest : public testing::Test {
SkBitmap CreateBlackSkBitmap(int width, int height) {
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
- bitmap.allocPixels();
- // Setting the pixels to black.
+ bitmap.allocN32Pixels(width, height);
+ // Setting the pixels to transparent-black.
memset(bitmap.getPixels(), 0, width * height * 4);
return bitmap;
}
@@ -172,23 +172,22 @@ TEST_F(IconUtilTest, TestBitmapToIconInvalidParameters) {
// Wrong bitmap format.
bitmap.reset(new SkBitmap);
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
- bitmap->setConfig(SkBitmap::kA8_Config, kSmallIconWidth, kSmallIconHeight);
+ bitmap->setInfo(SkImageInfo::MakeA8(kSmallIconWidth, kSmallIconHeight));
icon = IconUtil::CreateHICONFromSkBitmap(*bitmap);
EXPECT_EQ(icon, static_cast<HICON>(NULL));
// Invalid bitmap size.
bitmap.reset(new SkBitmap);
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
- bitmap->setConfig(SkBitmap::kARGB_8888_Config, 0, 0);
+ bitmap->setInfo(SkImageInfo::MakeN32Premul(0, 0));
icon = IconUtil::CreateHICONFromSkBitmap(*bitmap);
EXPECT_EQ(icon, static_cast<HICON>(NULL));
// Valid bitmap configuration but no pixels allocated.
bitmap.reset(new SkBitmap);
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
- bitmap->setConfig(SkBitmap::kARGB_8888_Config,
- kSmallIconWidth,
- kSmallIconHeight);
+ bitmap->setInfo(SkImageInfo::MakeN32Premul(kSmallIconWidth,
+ kSmallIconHeight));
icon = IconUtil::CreateHICONFromSkBitmap(*bitmap);
EXPECT_TRUE(icon == NULL);
}
@@ -206,10 +205,9 @@ TEST_F(IconUtilTest, TestCreateIconFileInvalidParameters) {
// Wrong bitmap format.
bitmap.reset(new SkBitmap);
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
- bitmap->setConfig(SkBitmap::kA8_Config, kSmallIconWidth, kSmallIconHeight);
// Must allocate pixels or else ImageSkia will ignore the bitmap and just
// return an empty image.
- bitmap->allocPixels();
+ bitmap->allocPixels(SkImageInfo::MakeA8(kSmallIconWidth, kSmallIconHeight));
memset(bitmap->getPixels(), 0, bitmap->width() * bitmap->height());
image_family.Add(gfx::Image::CreateFrom1xBitmap(*bitmap));
EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
@@ -220,8 +218,7 @@ TEST_F(IconUtilTest, TestCreateIconFileInvalidParameters) {
image_family.clear();
bitmap.reset(new SkBitmap);
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
- bitmap->setConfig(SkBitmap::kARGB_8888_Config, 0, 0);
- bitmap->allocPixels();
+ bitmap->allocPixels(SkImageInfo::MakeN32Premul(0, 0));
image_family.Add(gfx::Image::CreateFrom1xBitmap(*bitmap));
EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
valid_icon_filename));
@@ -231,9 +228,8 @@ TEST_F(IconUtilTest, TestCreateIconFileInvalidParameters) {
image_family.clear();
bitmap.reset(new SkBitmap);
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
- bitmap->setConfig(SkBitmap::kARGB_8888_Config,
- kSmallIconWidth,
- kSmallIconHeight);
+ bitmap->setInfo(SkImageInfo::MakeN32Premul(kSmallIconWidth,
+ kSmallIconHeight));
image_family.Add(gfx::Image::CreateFrom1xBitmap(*bitmap));
EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
valid_icon_filename));
@@ -284,7 +280,7 @@ TEST_F(IconUtilTest, TestCreateSkBitmapFromHICON) {
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
EXPECT_EQ(bitmap->width(), small_icon_size.width());
EXPECT_EQ(bitmap->height(), small_icon_size.height());
- EXPECT_EQ(bitmap->config(), SkBitmap::kARGB_8888_Config);
+ EXPECT_EQ(bitmap->colorType(), kPMColor_SkColorType);
::DestroyIcon(small_icon);
base::FilePath large_icon_filename = test_data_directory_.AppendASCII(
@@ -298,7 +294,7 @@ TEST_F(IconUtilTest, TestCreateSkBitmapFromHICON) {
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
EXPECT_EQ(bitmap->width(), large_icon_size.width());
EXPECT_EQ(bitmap->height(), large_icon_size.height());
- EXPECT_EQ(bitmap->config(), SkBitmap::kARGB_8888_Config);
+ EXPECT_EQ(bitmap->colorType(), kPMColor_SkColorType);
::DestroyIcon(large_icon);
}
diff --git a/chromium/ui/gfx/icon_util_unittests.ico b/chromium/ui/gfx/icon_util_unittests.ico
new file mode 100644
index 00000000000..8cd57a12299
--- /dev/null
+++ b/chromium/ui/gfx/icon_util_unittests.ico
Binary files differ
diff --git a/chromium/ui/gfx/icon_util_unittests.rc b/chromium/ui/gfx/icon_util_unittests.rc
new file mode 100644
index 00000000000..a44a001bc0b
--- /dev/null
+++ b/chromium/ui/gfx/icon_util_unittests.rc
@@ -0,0 +1,36 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "icon_util_unittests_resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME ICON "icon_util_unittests.ico"
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
diff --git a/chromium/ui/gfx/icon_util_unittests_resource.h b/chromium/ui/gfx/icon_util_unittests_resource.h
new file mode 100644
index 00000000000..0a50edfdd01
--- /dev/null
+++ b/chromium/ui/gfx/icon_util_unittests_resource.h
@@ -0,0 +1,5 @@
+// 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.
+
+#define IDR_MAINFRAME 101
diff --git a/chromium/ui/gfx/image/OWNERS b/chromium/ui/gfx/image/OWNERS
index d3273727c23..23dbb5a958f 100644
--- a/chromium/ui/gfx/image/OWNERS
+++ b/chromium/ui/gfx/image/OWNERS
@@ -1,4 +1,4 @@
rsesek@chromium.org
# ImageSkia related classes except for _mac/_ios stuff
-per-file image_skia.*=oshima@chromium.org
+per-file image_skia*=oshima@chromium.org
diff --git a/chromium/ui/gfx/image/cairo_cached_surface.cc b/chromium/ui/gfx/image/cairo_cached_surface.cc
deleted file mode 100644
index 2de4a3210b3..00000000000
--- a/chromium/ui/gfx/image/cairo_cached_surface.cc
+++ /dev/null
@@ -1,109 +0,0 @@
-// Copyright (c) 2011 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/image/cairo_cached_surface.h"
-
-#include <gtk/gtk.h>
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-
-namespace gfx {
-
-CairoCachedSurface::CairoCachedSurface() : pixbuf_(NULL) {
-}
-
-CairoCachedSurface::~CairoCachedSurface() {
- Reset();
-}
-
-void CairoCachedSurface::Reset() {
- for (SurfaceVector::iterator it = surface_map_.begin();
- it != surface_map_.end(); ++it) {
- cairo_surface_destroy(it->second);
- }
- surface_map_.clear();
-
- if (pixbuf_) {
- g_object_unref(pixbuf_);
- pixbuf_ = NULL;
- }
-}
-
-int CairoCachedSurface::Width() const {
- return pixbuf_ ? gdk_pixbuf_get_width(pixbuf_) : -1;
-}
-
-int CairoCachedSurface::Height() const {
- return pixbuf_ ? gdk_pixbuf_get_height(pixbuf_) : -1;
-}
-
-void CairoCachedSurface::UsePixbuf(GdkPixbuf* pixbuf) {
- if (pixbuf)
- g_object_ref(pixbuf);
-
- Reset();
-
- pixbuf_ = pixbuf;
-}
-
-void CairoCachedSurface::SetSource(cairo_t* cr, GtkWidget* widget,
- int x, int y) const {
- SetSource(cr, gtk_widget_get_display(widget), x, y);
-}
-
-void CairoCachedSurface::SetSource(cairo_t* cr, GdkDisplay* display,
- int x, int y) const {
- DCHECK(pixbuf_);
- DCHECK(cr);
- DCHECK(display);
-
- cairo_surface_t* surface = GetSurfaceFor(cr, display);
- cairo_set_source_surface(cr, surface, x, y);
-}
-
-void CairoCachedSurface::MaskSource(cairo_t* cr, GtkWidget* widget,
- int x, int y) const {
- MaskSource(cr, gtk_widget_get_display(widget), x, y);
-}
-
-void CairoCachedSurface::MaskSource(cairo_t* cr, GdkDisplay* display,
- int x, int y) const {
- DCHECK(pixbuf_);
- DCHECK(cr);
- DCHECK(display);
-
- cairo_surface_t* surface = GetSurfaceFor(cr, display);
- cairo_mask_surface(cr, surface, x, y);
-}
-
-cairo_surface_t* CairoCachedSurface::GetSurfaceFor(cairo_t* cr,
- GdkDisplay* display) const {
- for (SurfaceVector::const_iterator it = surface_map_.begin();
- it != surface_map_.end(); ++it) {
- if (display == it->first) {
- return it->second;
- }
- }
-
- // First time here since last UsePixbuf call. Generate the surface.
- cairo_surface_t* target = cairo_get_target(cr);
- cairo_surface_t* out = cairo_surface_create_similar(
- target,
- CAIRO_CONTENT_COLOR_ALPHA,
- gdk_pixbuf_get_width(pixbuf_),
- gdk_pixbuf_get_height(pixbuf_));
-
- DCHECK(out);
-
- cairo_t* copy_cr = cairo_create(out);
- gdk_cairo_set_source_pixbuf(copy_cr, pixbuf_, 0, 0);
- cairo_paint(copy_cr);
- cairo_destroy(copy_cr);
-
- surface_map_.push_back(std::make_pair(display, out));
- return out;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/image/cairo_cached_surface.h b/chromium/ui/gfx/image/cairo_cached_surface.h
deleted file mode 100644
index ceece4ba2d2..00000000000
--- a/chromium/ui/gfx/image/cairo_cached_surface.h
+++ /dev/null
@@ -1,84 +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_IMAGE_CAIRO_CACHED_SURFACE_H_
-#define UI_GFX_IMAGE_CAIRO_CACHED_SURFACE_H_
-
-#include <vector>
-
-#include "ui/gfx/gfx_export.h"
-
-typedef struct _GdkDisplay GdkDisplay;
-typedef struct _GdkPixbuf GdkPixbuf;
-typedef struct _GtkWidget GtkWidget;
-typedef struct _cairo cairo_t;
-typedef struct _cairo_surface cairo_surface_t;
-
-namespace gfx {
-
-// A helper class that takes a GdkPixbuf* and renders it to the screen. Unlike
-// gdk_cairo_set_source_pixbuf(), CairoCachedSurface assumes that the pixbuf is
-// immutable after UsePixbuf() is called and can be sent to the display server
-// once. From then on, that cached version is used so we don't upload the same
-// image each and every time we expose.
-//
-// Most cached surfaces are owned by the GtkThemeService, which associates
-// them with a certain XDisplay. Some users of surfaces (CustomDrawButtonBase,
-// for example) own their surfaces instead since they interact with the
-// ResourceBundle instead of the GtkThemeService.
-class GFX_EXPORT CairoCachedSurface {
- public:
- CairoCachedSurface();
- ~CairoCachedSurface();
-
- // Whether this CairoCachedSurface owns a GdkPixbuf.
- bool valid() const {
- return pixbuf_;
- }
-
- // Delete all our data.
- void Reset();
-
- // The dimensions of the underlying pixbuf/surface. (or -1 if invalid.)
- int Width() const;
- int Height() const;
-
- // Sets the pixbuf that we pass to cairo. Calling UsePixbuf() only derefs the
- // current pixbuf and surface (if they exist). Actually transfering data to
- // the X server occurs at SetSource() time. Calling UsePixbuf() should only
- // be done once as it clears cached data from the X server.
- void UsePixbuf(GdkPixbuf* pixbuf);
-
- // Sets our pixbuf as the active surface starting at (x, y), uploading it in
- // case we don't have an X backed surface cached.
- void SetSource(cairo_t* cr, GtkWidget* widget, int x, int y) const;
- void SetSource(cairo_t* cr, GdkDisplay* display, int x, int y) const;
-
- // Performs a mask operation, using this surface as the alpha channel.
- void MaskSource(cairo_t* cr, GtkWidget* widget, int x, int y) const;
- void MaskSource(cairo_t* cr, GdkDisplay* display, int x, int y) const;
-
- // Raw access to the pixbuf. May be NULL. Used for a few gdk operations
- // regarding window shaping.
- GdkPixbuf* pixbuf() { return pixbuf_; }
-
- private:
- typedef std::vector<std::pair<GdkDisplay*, cairo_surface_t*> > SurfaceVector;
-
- // Returns a surface . Caches results so only one copy of the image data
- // lives on the display server.
- cairo_surface_t* GetSurfaceFor(cairo_t* cr, GdkDisplay* display) const;
-
- // The source pixbuf.
- GdkPixbuf* pixbuf_;
-
- // Our list of cached surfaces. 99% of the time, this will only contain a
- // single entry. At most two. We need to get this right for multiple displays
- // to work correct, since each GdkDisplay is a different display server.
- mutable SurfaceVector surface_map_;
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_IMAGE_CAIRO_CACHED_SURFACE_H_
diff --git a/chromium/ui/gfx/image/image.cc b/chromium/ui/gfx/image/image.cc
index 91b9e69b289..459880742f8 100644
--- a/chromium/ui/gfx/image/image.cc
+++ b/chromium/ui/gfx/image/image.cc
@@ -5,6 +5,7 @@
#include "ui/gfx/image/image.h"
#include <algorithm>
+#include <set>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -12,21 +13,14 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/image/image_png_rep.h"
#include "ui/gfx/image/image_skia.h"
+#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/size.h"
#if !defined(OS_IOS)
#include "ui/gfx/codec/png_codec.h"
#endif
-#if defined(TOOLKIT_GTK)
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <gdk/gdk.h>
-#include <glib-object.h>
-#include "ui/gfx/canvas.h"
-#include "ui/gfx/gtk_util.h"
-#include "ui/gfx/image/cairo_cached_surface.h"
-#include "ui/gfx/scoped_gobject.h"
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
#include "base/mac/foundation_util.h"
#include "ui/gfx/image/image_skia_util_ios.h"
#elif defined(OS_MACOSX)
@@ -38,100 +32,25 @@ namespace gfx {
namespace internal {
-#if defined(TOOLKIT_GTK)
-const ImageSkia ImageSkiaFromGdkPixbuf(GdkPixbuf* pixbuf) {
- CHECK(pixbuf);
- gfx::Canvas canvas(gfx::Size(gdk_pixbuf_get_width(pixbuf),
- gdk_pixbuf_get_height(pixbuf)),
- 1.0f,
- false);
- skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas());
- cairo_t* cr = scoped_platform_paint.GetPlatformSurface();
- gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
- cairo_paint(cr);
- return ImageSkia(canvas.ExtractImageRep());
-}
-
-// Returns a 16x16 red pixbuf to visually show error in decoding PNG.
-// Also logs error to console.
-GdkPixbuf* GetErrorPixbuf() {
- LOG(ERROR) << "Unable to decode PNG.";
- GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 16, 16);
- gdk_pixbuf_fill(pixbuf, 0xff0000ff);
- return pixbuf;
-}
-
-GdkPixbuf* GdkPixbufFromPNG(
- const std::vector<gfx::ImagePNGRep>& image_png_reps) {
- scoped_refptr<base::RefCountedMemory> png_bytes(NULL);
- for (size_t i = 0; i < image_png_reps.size(); ++i) {
- if (image_png_reps[i].scale == 1.0f)
- png_bytes = image_png_reps[i].raw_data;
- }
-
- if (!png_bytes.get())
- return GetErrorPixbuf();
-
- GdkPixbuf* pixbuf = NULL;
- ui::ScopedGObject<GdkPixbufLoader>::Type loader(gdk_pixbuf_loader_new());
-
- bool ok = gdk_pixbuf_loader_write(loader.get(),
- reinterpret_cast<const guint8*>(png_bytes->front()), png_bytes->size(),
- NULL);
-
- // Calling gdk_pixbuf_loader_close forces the data to be parsed by the
- // loader. This must be done before calling gdk_pixbuf_loader_get_pixbuf.
- if (ok)
- ok = gdk_pixbuf_loader_close(loader.get(), NULL);
- if (ok)
- pixbuf = gdk_pixbuf_loader_get_pixbuf(loader.get());
-
- if (pixbuf) {
- // The pixbuf is owned by the scoped loader which will delete its ref when
- // it goes out of scope. Add a ref so that the pixbuf still exists.
- g_object_ref(pixbuf);
- } else {
- return GetErrorPixbuf();
- }
-
- return pixbuf;
-}
-
-scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromPixbuf(
- GdkPixbuf* pixbuf) {
- gchar* image = NULL;
- gsize image_size;
- GError* error = NULL;
- CHECK(gdk_pixbuf_save_to_buffer(
- pixbuf, &image, &image_size, "png", &error, NULL));
- scoped_refptr<base::RefCountedBytes> png_bytes(
- new base::RefCountedBytes());
- png_bytes->data().assign(image, image + image_size);
- g_free(image);
- return png_bytes;
-}
-
-#endif // defined(TOOLKIT_GTK)
-
#if defined(OS_IOS)
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage(
UIImage* uiimage);
// Caller takes ownership of the returned UIImage.
UIImage* CreateUIImageFromPNG(
- const std::vector<gfx::ImagePNGRep>& image_png_reps);
+ const std::vector<ImagePNGRep>& image_png_reps);
gfx::Size UIImageSize(UIImage* image);
#elif defined(OS_MACOSX)
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromNSImage(
NSImage* nsimage);
// Caller takes ownership of the returned NSImage.
-NSImage* NSImageFromPNG(const std::vector<gfx::ImagePNGRep>& image_png_reps,
+NSImage* NSImageFromPNG(const std::vector<ImagePNGRep>& image_png_reps,
CGColorSpaceRef color_space);
gfx::Size NSImageSize(NSImage* image);
#endif // defined(OS_MACOSX)
#if defined(OS_IOS)
ImageSkia* ImageSkiaFromPNG(
- const std::vector<gfx::ImagePNGRep>& image_png_reps);
+ const std::vector<ImagePNGRep>& image_png_reps);
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
const ImageSkia* skia);
#else
@@ -141,32 +60,92 @@ ImageSkia* GetErrorImageSkia() {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
bitmap.allocPixels();
- bitmap.eraseRGB(0xff, 0, 0);
- return new gfx::ImageSkia(gfx::ImageSkiaRep(bitmap, 1.0f));
+ bitmap.eraseARGB(0xff, 0xff, 0, 0);
+ return new ImageSkia(ImageSkiaRep(bitmap, 1.0f));
}
+class PNGImageSource : public ImageSkiaSource {
+ public:
+ PNGImageSource() {}
+ virtual ~PNGImageSource() {}
+
+ virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
+ if (image_skia_reps_.empty())
+ return ImageSkiaRep();
+
+ const ImageSkiaRep* rep = NULL;
+ // gfx::ImageSkia passes one of the resource scale factors. The source
+ // should return:
+ // 1) The ImageSkiaRep with the highest scale if all available
+ // scales are smaller than |scale|.
+ // 2) The ImageSkiaRep with the smallest one that is larger than |scale|.
+ for (ImageSkiaRepSet::const_iterator iter = image_skia_reps_.begin();
+ iter != image_skia_reps_.end(); ++iter) {
+ if ((*iter).scale() == scale)
+ return (*iter);
+ if (!rep || rep->scale() < (*iter).scale())
+ rep = &(*iter);
+ if (rep->scale() >= scale)
+ break;
+ }
+ return rep ? *rep : ImageSkiaRep();
+ }
+
+ const gfx::Size size() const {
+ return size_;
+ }
+
+ bool AddPNGData(const ImagePNGRep& png_rep) {
+ const gfx::ImageSkiaRep rep = ToImageSkiaRep(png_rep);
+ if (rep.is_null())
+ return false;
+ if (size_.IsEmpty())
+ size_ = gfx::Size(rep.GetWidth(), rep.GetHeight());
+ image_skia_reps_.insert(rep);
+ return true;
+ }
+
+ static ImageSkiaRep ToImageSkiaRep(const ImagePNGRep& png_rep) {
+ scoped_refptr<base::RefCountedMemory> raw_data = png_rep.raw_data;
+ CHECK(raw_data.get());
+ SkBitmap bitmap;
+ if (!PNGCodec::Decode(raw_data->front(), raw_data->size(),
+ &bitmap)) {
+ LOG(ERROR) << "Unable to decode PNG for " << png_rep.scale << ".";
+ return ImageSkiaRep();
+ }
+ return ImageSkiaRep(bitmap, png_rep.scale);
+ }
+
+ private:
+ struct Compare {
+ bool operator()(const ImageSkiaRep& rep1, const ImageSkiaRep& rep2) {
+ return rep1.scale() < rep2.scale();
+ }
+ };
+
+ typedef std::set<ImageSkiaRep, Compare> ImageSkiaRepSet;
+ ImageSkiaRepSet image_skia_reps_;
+ gfx::Size size_;
+
+ DISALLOW_COPY_AND_ASSIGN(PNGImageSource);
+};
+
ImageSkia* ImageSkiaFromPNG(
- const std::vector<gfx::ImagePNGRep>& image_png_reps) {
+ const std::vector<ImagePNGRep>& image_png_reps) {
if (image_png_reps.empty())
return GetErrorImageSkia();
+ scoped_ptr<PNGImageSource> image_source(new PNGImageSource);
- scoped_ptr<gfx::ImageSkia> image_skia(new ImageSkia());
for (size_t i = 0; i < image_png_reps.size(); ++i) {
- scoped_refptr<base::RefCountedMemory> raw_data =
- image_png_reps[i].raw_data;
- CHECK(raw_data.get());
- SkBitmap bitmap;
- if (!gfx::PNGCodec::Decode(raw_data->front(), raw_data->size(),
- &bitmap)) {
- LOG(ERROR) << "Unable to decode PNG for "
- << image_png_reps[i].scale
- << ".";
+ if (!image_source->AddPNGData(image_png_reps[i]))
return GetErrorImageSkia();
- }
- image_skia->AddRepresentation(gfx::ImageSkiaRep(
- bitmap, image_png_reps[i].scale));
}
- return image_skia.release();
+ const gfx::Size& size = image_source->size();
+ DCHECK(!size.IsEmpty());
+ if (size.IsEmpty())
+ return GetErrorImageSkia();
+ return new ImageSkia(image_source.release(), size);
}
scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
@@ -175,7 +154,7 @@ scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
scoped_refptr<base::RefCountedBytes> png_bytes(new base::RefCountedBytes());
if (image_skia_rep.scale() != 1.0f ||
- !gfx::PNGCodec::EncodeBGRASkBitmap(image_skia_rep.sk_bitmap(), false,
+ !PNGCodec::EncodeBGRASkBitmap(image_skia_rep.sk_bitmap(), false,
&png_bytes->data())) {
return NULL;
}
@@ -185,8 +164,6 @@ scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia(
class ImageRepPNG;
class ImageRepSkia;
-class ImageRepGdk;
-class ImageRepCairo;
class ImageRepCocoa;
class ImageRepCocoaTouch;
@@ -213,18 +190,6 @@ class ImageRep {
return reinterpret_cast<ImageRepSkia*>(this);
}
-#if defined(TOOLKIT_GTK)
- ImageRepGdk* AsImageRepGdk() {
- CHECK_EQ(type_, Image::kImageRepGdk);
- return reinterpret_cast<ImageRepGdk*>(this);
- }
-
- ImageRepCairo* AsImageRepCairo() {
- CHECK_EQ(type_, Image::kImageRepCairo);
- return reinterpret_cast<ImageRepCairo*>(this);
- }
-#endif
-
#if defined(OS_IOS)
ImageRepCocoaTouch* AsImageRepCocoaTouch() {
CHECK_EQ(type_, Image::kImageRepCocoaTouch);
@@ -326,77 +291,6 @@ class ImageRepSkia : public ImageRep {
DISALLOW_COPY_AND_ASSIGN(ImageRepSkia);
};
-#if defined(TOOLKIT_GTK)
-class ImageRepGdk : public ImageRep {
- public:
- explicit ImageRepGdk(GdkPixbuf* pixbuf)
- : ImageRep(Image::kImageRepGdk),
- pixbuf_(pixbuf) {
- CHECK(pixbuf);
- }
-
- virtual ~ImageRepGdk() {
- if (pixbuf_) {
- g_object_unref(pixbuf_);
- pixbuf_ = NULL;
- }
- }
-
- virtual int Width() const OVERRIDE {
- return gdk_pixbuf_get_width(pixbuf_);
- }
-
- virtual int Height() const OVERRIDE {
- return gdk_pixbuf_get_height(pixbuf_);
- }
-
- virtual gfx::Size Size() const OVERRIDE {
- return gfx::Size(Width(), Height());
- }
-
- GdkPixbuf* pixbuf() const { return pixbuf_; }
-
- private:
- GdkPixbuf* pixbuf_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageRepGdk);
-};
-
-// Represents data that lives on the display server instead of in the client.
-class ImageRepCairo : public ImageRep {
- public:
- explicit ImageRepCairo(GdkPixbuf* pixbuf)
- : ImageRep(Image::kImageRepCairo),
- cairo_cache_(new CairoCachedSurface) {
- CHECK(pixbuf);
- cairo_cache_->UsePixbuf(pixbuf);
- }
-
- virtual ~ImageRepCairo() {
- delete cairo_cache_;
- }
-
- virtual int Width() const OVERRIDE {
- return cairo_cache_->Width();
- }
-
- virtual int Height() const OVERRIDE {
- return cairo_cache_->Height();
- }
-
- virtual gfx::Size Size() const OVERRIDE {
- return gfx::Size(Width(), Height());
- }
-
- CairoCachedSurface* surface() const { return cairo_cache_; }
-
- private:
- CairoCachedSurface* cairo_cache_;
-
- DISALLOW_COPY_AND_ASSIGN(ImageRepCairo);
-};
-#endif // defined(TOOLKIT_GTK)
-
#if defined(OS_IOS)
class ImageRepCocoaTouch : public ImageRep {
public:
@@ -470,7 +364,7 @@ class ImageRepCocoa : public ImageRep {
// ImageReps. This way, the Image can be cheaply copied.
class ImageStorage : public base::RefCounted<ImageStorage> {
public:
- ImageStorage(gfx::Image::RepresentationType default_type)
+ ImageStorage(Image::RepresentationType default_type)
: default_representation_type_(default_type),
#if defined(OS_MACOSX) && !defined(OS_IOS)
default_representation_color_space_(
@@ -479,10 +373,10 @@ class ImageStorage : public base::RefCounted<ImageStorage> {
representations_deleter_(&representations_) {
}
- gfx::Image::RepresentationType default_representation_type() {
+ Image::RepresentationType default_representation_type() {
return default_representation_type_;
}
- gfx::Image::RepresentationMap& representations() { return representations_; }
+ Image::RepresentationMap& representations() { return representations_; }
#if defined(OS_MACOSX) && !defined(OS_IOS)
void set_default_representation_color_space(CGColorSpaceRef color_space) {
@@ -500,7 +394,7 @@ class ImageStorage : public base::RefCounted<ImageStorage> {
// The type of image that was passed to the constructor. This key will always
// exist in the |representations_| map.
- gfx::Image::RepresentationType default_representation_type_;
+ Image::RepresentationType default_representation_type_;
#if defined(OS_MACOSX) && !defined(OS_IOS)
// The default representation's colorspace. This is used for converting to
@@ -512,7 +406,7 @@ class ImageStorage : public base::RefCounted<ImageStorage> {
// All the representations of an Image. Size will always be at least one, with
// more for any converted representations.
- gfx::Image::RepresentationMap representations_;
+ Image::RepresentationMap representations_;
STLValueDeleter<Image::RepresentationMap> representations_deleter_;
@@ -550,16 +444,6 @@ Image::Image(const ImageSkia& image) {
}
}
-#if defined(TOOLKIT_GTK)
-Image::Image(GdkPixbuf* pixbuf) {
- if (pixbuf) {
- storage_ = new internal::ImageStorage(Image::kImageRepGdk);
- internal::ImageRepGdk* rep = new internal::ImageRepGdk(pixbuf);
- AddRepresentation(rep);
- }
-}
-#endif
-
#if defined(OS_IOS)
Image::Image(UIImage* image)
: storage_(new internal::ImageStorage(Image::kImageRepCocoaTouch)) {
@@ -591,20 +475,29 @@ Image::~Image() {
// static
Image Image::CreateFrom1xBitmap(const SkBitmap& bitmap) {
- return gfx::Image(ImageSkia::CreateFrom1xBitmap(bitmap));
+ return Image(ImageSkia::CreateFrom1xBitmap(bitmap));
}
// static
Image Image::CreateFrom1xPNGBytes(const unsigned char* input,
size_t input_size) {
if (input_size == 0u)
- return gfx::Image();
+ return Image();
scoped_refptr<base::RefCountedBytes> raw_data(new base::RefCountedBytes());
raw_data->data().assign(input, input + input_size);
- std::vector<gfx::ImagePNGRep> image_reps;
- image_reps.push_back(ImagePNGRep(raw_data, 1.0f));
- return gfx::Image(image_reps);
+
+ return CreateFrom1xPNGBytes(raw_data);
+}
+
+Image Image::CreateFrom1xPNGBytes(
+ const scoped_refptr<base::RefCountedMemory>& input) {
+ if (!input.get() || input->size() == 0u)
+ return Image();
+
+ std::vector<ImagePNGRep> image_reps;
+ image_reps.push_back(ImagePNGRep(input, 1.0f));
+ return Image(image_reps);
}
const SkBitmap* Image::ToSkBitmap() const {
@@ -623,15 +516,7 @@ const ImageSkia* Image::ToImageSkia() const {
internal::ImageSkiaFromPNG(png_rep->image_reps()));
break;
}
-#if defined(TOOLKIT_GTK)
- case kImageRepGdk: {
- internal::ImageRepGdk* native_rep =
- GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
- rep = new internal::ImageRepSkia(new ImageSkia(
- internal::ImageSkiaFromGdkPixbuf(native_rep->pixbuf())));
- break;
- }
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
case kImageRepCocoaTouch: {
internal::ImageRepCocoaTouch* native_rep =
GetRepresentation(kImageRepCocoaTouch, true)
@@ -658,47 +543,6 @@ const ImageSkia* Image::ToImageSkia() const {
return rep->AsImageRepSkia()->image();
}
-#if defined(TOOLKIT_GTK)
-GdkPixbuf* Image::ToGdkPixbuf() const {
- internal::ImageRep* rep = GetRepresentation(kImageRepGdk, false);
- if (!rep) {
- switch (DefaultRepresentationType()) {
- case kImageRepPNG: {
- internal::ImageRepPNG* png_rep =
- GetRepresentation(kImageRepPNG, true)->AsImageRepPNG();
- rep = new internal::ImageRepGdk(internal::GdkPixbufFromPNG(
- png_rep->image_reps()));
- break;
- }
- case kImageRepSkia: {
- internal::ImageRepSkia* skia_rep =
- GetRepresentation(kImageRepSkia, true)->AsImageRepSkia();
- rep = new internal::ImageRepGdk(gfx::GdkPixbufFromSkBitmap(
- *skia_rep->image()->bitmap()));
- break;
- }
- default:
- NOTREACHED();
- }
- CHECK(rep);
- AddRepresentation(rep);
- }
- return rep->AsImageRepGdk()->pixbuf();
-}
-
-CairoCachedSurface* const Image::ToCairo() const {
- internal::ImageRep* rep = GetRepresentation(kImageRepCairo, false);
- if (!rep) {
- // Handle any-to-Cairo conversion. This may create and cache an intermediate
- // pixbuf before sending the data to the display server.
- rep = new internal::ImageRepCairo(ToGdkPixbuf());
- CHECK(rep);
- AddRepresentation(rep);
- }
- return rep->AsImageRepCairo()->surface();
-}
-#endif
-
#if defined(OS_IOS)
UIImage* Image::ToUIImage() const {
internal::ImageRep* rep = GetRepresentation(kImageRepCocoaTouch, false);
@@ -768,7 +612,7 @@ scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const {
internal::ImageRep* rep = GetRepresentation(kImageRepPNG, false);
if (rep) {
- const std::vector<gfx::ImagePNGRep>& image_png_reps =
+ 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)
@@ -779,14 +623,7 @@ scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const {
scoped_refptr<base::RefCountedMemory> png_bytes(NULL);
switch (DefaultRepresentationType()) {
-#if defined(TOOLKIT_GTK)
- case kImageRepGdk: {
- internal::ImageRepGdk* gdk_rep =
- GetRepresentation(kImageRepGdk, true)->AsImageRepGdk();
- png_bytes = internal::Get1xPNGBytesFromPixbuf(gdk_rep->pixbuf());
- break;
- }
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
case kImageRepCocoaTouch: {
internal::ImageRepCocoaTouch* cocoa_touch_rep =
GetRepresentation(kImageRepCocoaTouch, true)
@@ -826,7 +663,7 @@ scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const {
// final type eg (converting from ImageRepSkia to ImageRepPNG to get an
// ImageRepCocoa).
std::vector<ImagePNGRep> image_png_reps;
- image_png_reps.push_back(gfx::ImagePNGRep(png_bytes, 1.0f));
+ image_png_reps.push_back(ImagePNGRep(png_bytes, 1.0f));
rep = new internal::ImageRepPNG(image_png_reps);
AddRepresentation(rep);
return png_bytes;
@@ -861,14 +698,6 @@ SkBitmap* Image::CopySkBitmap() const {
return new SkBitmap(*ToSkBitmap());
}
-#if defined(TOOLKIT_GTK)
-GdkPixbuf* Image::CopyGdkPixbuf() const {
- GdkPixbuf* pixbuf = ToGdkPixbuf();
- g_object_ref(pixbuf);
- return pixbuf;
-}
-#endif
-
#if defined(OS_IOS)
UIImage* Image::CopyUIImage() const {
UIImage* image = ToUIImage();
@@ -916,7 +745,7 @@ gfx::Size Image::Size() const {
return GetRepresentation(DefaultRepresentationType(), true)->Size();
}
-void Image::SwapRepresentations(gfx::Image* other) {
+void Image::SwapRepresentations(Image* other) {
storage_.swap(other->storage_);
}
@@ -929,11 +758,7 @@ void Image::SetSourceColorSpace(CGColorSpaceRef color_space) {
Image::RepresentationType Image::DefaultRepresentationType() const {
CHECK(storage_.get());
- RepresentationType default_type = storage_->default_representation_type();
- // The conversions above assume that the default representation type is never
- // kImageRepCairo.
- DCHECK_NE(default_type, kImageRepCairo);
- return default_type;
+ return storage_->default_representation_type();
}
internal::ImageRep* Image::GetRepresentation(
diff --git a/chromium/ui/gfx/image/image.h b/chromium/ui/gfx/image/image.h
index d4093b74063..19ca93dada9 100644
--- a/chromium/ui/gfx/image/image.h
+++ b/chromium/ui/gfx/image/image.h
@@ -44,10 +44,6 @@ struct ImagePNGRep;
class ImageSkia;
class Size;
-#if defined(TOOLKIT_GTK)
-class CairoCachedSurface;
-#endif
-
namespace internal {
class ImageRep;
class ImageStorage;
@@ -56,10 +52,8 @@ class ImageStorage;
class GFX_EXPORT Image {
public:
enum RepresentationType {
- kImageRepGdk,
kImageRepCocoa,
kImageRepCocoaTouch,
- kImageRepCairo,
kImageRepSkia,
kImageRepPNG,
};
@@ -77,10 +71,7 @@ class GFX_EXPORT Image {
// representation.
explicit Image(const ImageSkia& image);
-#if defined(TOOLKIT_GTK)
- // Does not increase |pixbuf|'s reference count; expects to take ownership.
- explicit Image(GdkPixbuf* pixbuf);
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
// Does not retain |image|; expects to take ownership.
explicit Image(UIImage* image);
#elif defined(OS_MACOSX)
@@ -113,15 +104,16 @@ class GFX_EXPORT Image {
static Image CreateFrom1xPNGBytes(const unsigned char* input,
size_t input_size);
+ // Creates an image from the PNG encoded input.
+ static Image CreateFrom1xPNGBytes(
+ const scoped_refptr<base::RefCountedMemory>& input);
+
// Converts the Image to the desired representation and stores it internally.
// The returned result is a weak pointer owned by and scoped to the life of
// the Image. Must only be called if IsEmpty() is false.
const SkBitmap* ToSkBitmap() const;
const ImageSkia* ToImageSkia() const;
-#if defined(TOOLKIT_GTK)
- GdkPixbuf* ToGdkPixbuf() const;
- CairoCachedSurface* const ToCairo() const;
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
UIImage* ToUIImage() const;
#elif defined(OS_MACOSX)
NSImage* ToNSImage() const;
@@ -154,9 +146,7 @@ class GFX_EXPORT Image {
scoped_refptr<base::RefCountedMemory> Copy1xPNGBytes() const;
ImageSkia* CopyImageSkia() const;
SkBitmap* CopySkBitmap() const;
-#if defined(TOOLKIT_GTK)
- GdkPixbuf* CopyGdkPixbuf() const;
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
UIImage* CopyUIImage() const;
#elif defined(OS_MACOSX)
NSImage* CopyNSImage() const;
diff --git a/chromium/ui/gfx/image/image_skia.cc b/chromium/ui/gfx/image/image_skia.cc
index a283117db24..21d08de3003 100644
--- a/chromium/ui/gfx/image/image_skia.cc
+++ b/chromium/ui/gfx/image/image_skia.cc
@@ -8,14 +8,17 @@
#include <cmath>
#include <limits>
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/non_thread_safe.h"
+#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "ui/gfx/skia_util.h"
+#include "ui/gfx/switches.h"
namespace gfx {
namespace {
@@ -27,6 +30,13 @@ gfx::ImageSkiaRep& NullImageRep() {
}
std::vector<float>* g_supported_scales = NULL;
+
+// The difference to fall back to the smaller scale factor rather than the
+// larger one. For example, assume 1.25 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.
+const float kFallbackToSmallerScaleDiff = 0.25f;
+
} // namespace
namespace internal {
@@ -102,12 +112,36 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>,
return (read_only_ && !source_.get()) || CalledOnValidThread();
}
+ // Add a new representation. This checks if the scale of the added image
+ // is not 1.0f, and mark the existing rep as scaled to make
+ // the image high DPI aware.
+ void AddRepresentation(const ImageSkiaRep& image) {
+ if (image.scale() != 1.0f) {
+ for (ImageSkia::ImageSkiaReps::iterator it = image_reps_.begin();
+ it < image_reps_.end();
+ ++it) {
+ if (it->unscaled()) {
+ DCHECK_EQ(1.0f, it->scale());
+ it->SetScaled();
+ break;
+ }
+ }
+ }
+ image_reps_.push_back(image);
+ }
+
// Returns the iterator of the image rep whose density best matches
// |scale|. If the image for the |scale| doesn't exist in the storage and
// |storage| is set, it fetches new image by calling
- // |ImageSkiaSource::GetImageForScale|. If the source returns the image with
- // different scale (if the image doesn't exist in resource, for example), it
- // will fallback to closest image rep.
+ // |ImageSkiaSource::GetImageForScale|. There are two modes to deal with
+ // arbitrary scale factors.
+ // 1: Invoke GetImageForScale with requested scale and if the source
+ // returns the image with different scale (if the image doesn't exist in
+ // resource, for example), it will fallback to closest image rep.
+ // 2: Invoke GetImageForScale with the closest known scale to the requested
+ // one and rescale the image.
+ // Right now only Windows uses 2 and other platforms use 1 by default.
+ // TODO(mukai, oshima): abandon 1 code path and use 2 for every platforms.
std::vector<ImageSkiaRep>::iterator FindRepresentation(
float scale, bool fetch_new_image) const {
ImageSkiaStorage* non_const = const_cast<ImageSkiaStorage*>(this);
@@ -139,7 +173,47 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>,
DCHECK(CalledOnValidThread()) <<
"An ImageSkia with the source must be accessed by the same thread.";
- ImageSkiaRep image = source_->GetImageForScale(scale);
+ ImageSkiaRep image;
+ float resource_scale = scale;
+ if (ImageSkia::IsDSFScalingInImageSkiaEnabled() && g_supported_scales) {
+ if (g_supported_scales->back() <= scale) {
+ resource_scale = g_supported_scales->back();
+ } else {
+ for (size_t i = 0; i < g_supported_scales->size(); ++i) {
+ if ((*g_supported_scales)[i] + kFallbackToSmallerScaleDiff >=
+ scale) {
+ resource_scale = (*g_supported_scales)[i];
+ break;
+ }
+ }
+ }
+ }
+ if (ImageSkia::IsDSFScalingInImageSkiaEnabled() &&
+ scale != resource_scale) {
+ std::vector<ImageSkiaRep>::iterator iter = FindRepresentation(
+ resource_scale, fetch_new_image);
+
+ DCHECK(iter != image_reps_.end());
+
+ if (!iter->unscaled()) {
+ SkBitmap scaled_image;
+ gfx::Size unscaled_size(iter->pixel_width(), iter->pixel_height());
+ gfx::Size scaled_size = ToCeiledSize(
+ gfx::ScaleSize(unscaled_size, scale / iter->scale()));
+
+ image = ImageSkiaRep(skia::ImageOperations::Resize(
+ iter->sk_bitmap(),
+ skia::ImageOperations::RESIZE_LANCZOS3,
+ scaled_size.width(),
+ scaled_size.height()), scale);
+ DCHECK_EQ(image.pixel_width(), scaled_size.width());
+ DCHECK_EQ(image.pixel_height(), scaled_size.height());
+ } else {
+ image = *iter;
+ }
+ } else {
+ image = source_->GetImageForScale(scale);
+ }
// If the source returned the new image, store it.
if (!image.is_null() &&
@@ -240,7 +314,13 @@ float ImageSkia::GetMaxSupportedScale() {
// static
ImageSkia ImageSkia::CreateFrom1xBitmap(const SkBitmap& bitmap) {
- return ImageSkia(ImageSkiaRep(bitmap, 1.0f));
+ return ImageSkia(ImageSkiaRep(bitmap, 0.0f));
+}
+
+bool ImageSkia::IsDSFScalingInImageSkiaEnabled() {
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ return !command_line->HasSwitch(
+ switches::kDisableArbitraryScaleFactorInImageSkia);
}
scoped_ptr<ImageSkia> ImageSkia::DeepCopy() const {
@@ -278,7 +358,9 @@ void ImageSkia::AddRepresentation(const ImageSkiaRep& image_rep) {
Init(image_rep);
} else {
CHECK(CanModify());
- storage_->image_reps().push_back(image_rep);
+ // If someone is adding ImageSkia explicitly, check if we should
+ // make the image high DPI aware.
+ storage_->AddRepresentation(image_rep);
}
}
diff --git a/chromium/ui/gfx/image/image_skia.h b/chromium/ui/gfx/image/image_skia.h
index fa5d070ad9b..8765457b432 100644
--- a/chromium/ui/gfx/image/image_skia.h
+++ b/chromium/ui/gfx/image/image_skia.h
@@ -78,6 +78,10 @@ class GFX_EXPORT ImageSkia {
// density display.
static ImageSkia CreateFrom1xBitmap(const SkBitmap& bitmap);
+ // Returns true when ImageSkia looks up the resource pack with the closest
+ // scale factor and rescale the fetched image.
+ static bool IsDSFScalingInImageSkiaEnabled();
+
// Returns a deep copy of this ImageSkia which has its own storage with
// the ImageSkiaRep instances that this ImageSkia currently has.
// This can be safely passed to and manipulated by another thread.
diff --git a/chromium/ui/gfx/image/image_skia_rep.cc b/chromium/ui/gfx/image/image_skia_rep.cc
index f8f3acb1946..f31db600465 100644
--- a/chromium/ui/gfx/image/image_skia_rep.cc
+++ b/chromium/ui/gfx/image/image_skia_rep.cc
@@ -4,9 +4,11 @@
#include "ui/gfx/image/image_skia_rep.h"
+#include "base/logging.h"
+
namespace gfx {
-ImageSkiaRep::ImageSkiaRep() : scale_(1.0f) {
+ImageSkiaRep::ImageSkiaRep() : scale_(0.0f) {
}
ImageSkiaRep::~ImageSkiaRep() {
@@ -14,9 +16,10 @@ ImageSkiaRep::~ImageSkiaRep() {
ImageSkiaRep::ImageSkiaRep(const gfx::Size& size, float scale) : scale_(scale) {
bitmap_.setConfig(SkBitmap::kARGB_8888_Config,
- static_cast<int>(size.width() * scale),
- static_cast<int>(size.height() * scale));
+ static_cast<int>(size.width() * this->scale()),
+ static_cast<int>(size.height() * this->scale()));
bitmap_.allocPixels();
+ bitmap_.eraseColor(SK_ColorRED);
}
ImageSkiaRep::ImageSkiaRep(const SkBitmap& src, float scale)
@@ -25,11 +28,17 @@ ImageSkiaRep::ImageSkiaRep(const SkBitmap& src, float scale)
}
int ImageSkiaRep::GetWidth() const {
- return static_cast<int>(bitmap_.width() / scale_);
+ return static_cast<int>(bitmap_.width() / scale());
}
int ImageSkiaRep::GetHeight() const {
- return static_cast<int>(bitmap_.height() / scale_);
+ return static_cast<int>(bitmap_.height() / scale());
+}
+
+void ImageSkiaRep::SetScaled() {
+ DCHECK_EQ(0.0f, scale_);
+ if (scale_ == 0.0f)
+ scale_ = 1.0f;
}
} // namespace gfx
diff --git a/chromium/ui/gfx/image/image_skia_rep.h b/chromium/ui/gfx/image/image_skia_rep.h
index 7a1e83709ab..47f6713acf5 100644
--- a/chromium/ui/gfx/image/image_skia_rep.h
+++ b/chromium/ui/gfx/image/image_skia_rep.h
@@ -12,14 +12,20 @@
namespace gfx {
// An ImageSkiaRep represents a bitmap and the scale factor it is intended for.
+// 0.0f scale is used to indicate that this ImageSkiaRep is used for unscaled
+// image (the image that only returns 1.0f scale image).
class GFX_EXPORT ImageSkiaRep {
public:
// Create null bitmap.
ImageSkiaRep();
~ImageSkiaRep();
+ // Note: This is for testing purpose only.
// Creates a bitmap with kARGB_8888_Config config with given |size| in DIP.
- // This allocates pixels in the bitmap.
+ // This allocates pixels in the bitmap. It is guaranteed that the data in the
+ // bitmap are initialized but the actual values are undefined.
+ // Specifying 0 scale means the image is for unscaled image. (unscaled()
+ // returns truen, and scale() returns 1.0f;)
ImageSkiaRep(const gfx::Size& size, float scale);
// Creates a bitmap with given scale.
@@ -41,7 +47,12 @@ class GFX_EXPORT ImageSkiaRep {
}
// Retrieves the scale that the bitmap will be painted at.
- float scale() const { return scale_; }
+ float scale() const { return unscaled() ? 1.0f : scale_; }
+
+ bool unscaled() const { return scale_ == 0.0f; }
+
+ // Mark the image to be used as scaled image.
+ void SetScaled();
// Returns backing bitmap.
const SkBitmap& sk_bitmap() const { return bitmap_; }
@@ -51,6 +62,7 @@ class GFX_EXPORT ImageSkiaRep {
SkBitmap& mutable_sk_bitmap() { return bitmap_; }
SkBitmap bitmap_;
+
float scale_;
};
diff --git a/chromium/ui/gfx/image/image_skia_unittest.cc b/chromium/ui/gfx/image/image_skia_unittest.cc
index 0047822122b..e3e93c73b78 100644
--- a/chromium/ui/gfx/image/image_skia_unittest.cc
+++ b/chromium/ui/gfx/image/image_skia_unittest.cc
@@ -4,6 +4,7 @@
#include "ui/gfx/image/image_skia.h"
+#include "base/command_line.h"
#include "base/logging.h"
#include "base/threading/simple_thread.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -11,6 +12,7 @@
#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/size.h"
+#include "ui/gfx/switches.h"
// Duplicated from base/threading/non_thread_safe.h so that we can be
// good citizens there and undef the macro.
@@ -43,17 +45,27 @@ class FixedSource : public ImageSkiaSource {
class DynamicSource : public ImageSkiaSource {
public:
- DynamicSource(const gfx::Size& size) : size_(size) {}
+ DynamicSource(const gfx::Size& size)
+ : size_(size),
+ last_requested_scale_(0.0f) {}
virtual ~DynamicSource() {
}
virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
+ last_requested_scale_ = scale;
return gfx::ImageSkiaRep(size_, scale);
}
+ float GetLastRequestedScaleAndReset() {
+ float result = last_requested_scale_;
+ last_requested_scale_ = 0.0f;
+ return result;
+ }
+
private:
gfx::Size size_;
+ float last_requested_scale_;
DISALLOW_COPY_AND_ASSIGN(DynamicSource);
};
@@ -113,7 +125,28 @@ class TestOnThread : public base::SimpleThread {
} // namespace test
-TEST(ImageSkiaTest, FixedSource) {
+class ImageSkiaTest : public testing::Test {
+ public:
+ ImageSkiaTest() {
+ // In the test, we assume that we support 1.0f and 2.0f DSFs.
+ old_scales_ = ImageSkia::GetSupportedScales();
+
+ // Sets the list of scale factors supported by resource bundle.
+ std::vector<float> supported_scales;
+ supported_scales.push_back(1.0f);
+ supported_scales.push_back(2.0f);
+ ImageSkia::SetSupportedScales(supported_scales);
+ }
+ virtual ~ImageSkiaTest() {
+ ImageSkia::SetSupportedScales(old_scales_);
+ }
+
+ private:
+ std::vector<float> old_scales_;
+ DISALLOW_COPY_AND_ASSIGN(ImageSkiaTest);
+};
+
+TEST_F(ImageSkiaTest, FixedSource) {
ImageSkiaRep image(Size(100, 200), 1.0f);
ImageSkia image_skia(new FixedSource(image), Size(100, 200));
EXPECT_EQ(0U, image_skia.image_reps().size());
@@ -140,7 +173,7 @@ TEST(ImageSkiaTest, FixedSource) {
EXPECT_EQ(1U, image_skia.image_reps().size());
}
-TEST(ImageSkiaTest, DynamicSource) {
+TEST_F(ImageSkiaTest, DynamicSource) {
ImageSkia image_skia(new DynamicSource(Size(100, 200)), Size(100, 200));
EXPECT_EQ(0U, image_skia.image_reps().size());
const ImageSkiaRep& result_100p = image_skia.GetRepresentation(1.0f);
@@ -169,7 +202,7 @@ TEST(ImageSkiaTest, DynamicSource) {
// Tests that image_reps returns all of the representations in the
// image when there are multiple representations for a scale factor.
// This currently is the case with ImageLoader::LoadImages.
-TEST(ImageSkiaTest, ManyRepsPerScaleFactor) {
+TEST_F(ImageSkiaTest, ManyRepsPerScaleFactor) {
const int kSmallIcon1x = 16;
const int kSmallIcon2x = 32;
const int kLargeIcon1x = 32;
@@ -204,14 +237,14 @@ TEST(ImageSkiaTest, ManyRepsPerScaleFactor) {
EXPECT_EQ(1, num_2x);
}
-TEST(ImageSkiaTest, GetBitmap) {
+TEST_F(ImageSkiaTest, GetBitmap) {
ImageSkia image_skia(new DynamicSource(Size(100, 200)), Size(100, 200));
const SkBitmap* bitmap = image_skia.bitmap();
EXPECT_NE(static_cast<SkBitmap*>(NULL), bitmap);
EXPECT_FALSE(bitmap->isNull());
}
-TEST(ImageSkiaTest, GetBitmapFromEmpty) {
+TEST_F(ImageSkiaTest, GetBitmapFromEmpty) {
// Create an image with 1 representation and remove it so the ImageSkiaStorage
// is left with no representations.
ImageSkia empty_image(ImageSkiaRep(Size(100, 200), 1.0f));
@@ -226,7 +259,7 @@ TEST(ImageSkiaTest, GetBitmapFromEmpty) {
EXPECT_TRUE(bitmap->empty());
}
-TEST(ImageSkiaTest, BackedBySameObjectAs) {
+TEST_F(ImageSkiaTest, BackedBySameObjectAs) {
// Null images should all be backed by the same object (NULL).
ImageSkia image;
ImageSkia unrelated;
@@ -245,7 +278,7 @@ TEST(ImageSkiaTest, BackedBySameObjectAs) {
}
#if ENABLE_NON_THREAD_SAFE
-TEST(ImageSkiaTest, EmptyOnThreadTest) {
+TEST_F(ImageSkiaTest, EmptyOnThreadTest) {
ImageSkia empty;
test::TestOnThread empty_on_thread(&empty);
empty_on_thread.Start();
@@ -254,7 +287,7 @@ TEST(ImageSkiaTest, EmptyOnThreadTest) {
EXPECT_TRUE(empty_on_thread.can_modify());
}
-TEST(ImageSkiaTest, StaticOnThreadTest) {
+TEST_F(ImageSkiaTest, StaticOnThreadTest) {
ImageSkia image(ImageSkiaRep(Size(100, 200), 1.0f));
EXPECT_FALSE(image.IsThreadSafe());
@@ -323,7 +356,7 @@ TEST(ImageSkiaTest, StaticOnThreadTest) {
EXPECT_FALSE(image.CanModify());
}
-TEST(ImageSkiaTest, SourceOnThreadTest) {
+TEST_F(ImageSkiaTest, SourceOnThreadTest) {
ImageSkia image(new DynamicSource(Size(100, 200)), Size(100, 200));
EXPECT_FALSE(image.IsThreadSafe());
@@ -375,4 +408,136 @@ TEST(ImageSkiaTest, SourceOnThreadTest) {
// Just in case we ever get lumped together with other compilation units.
#undef ENABLE_NON_THREAD_SAFE
+TEST_F(ImageSkiaTest, Unscaled) {
+ SkBitmap bitmap;
+
+ // An ImageSkia created with 1x bitmap is unscaled.
+ ImageSkia image_skia = ImageSkia::CreateFrom1xBitmap(bitmap);
+ EXPECT_TRUE(image_skia.GetRepresentation(1.0f).unscaled());
+ ImageSkiaRep rep_2x(Size(100, 100), 2.0f);
+
+ // When reps for other scales are added, the unscaled image
+ // becomes scaled.
+ image_skia.AddRepresentation(rep_2x);
+ EXPECT_FALSE(image_skia.GetRepresentation(1.0f).unscaled());
+ EXPECT_FALSE(image_skia.GetRepresentation(2.0f).unscaled());
+}
+
+TEST_F(ImageSkiaTest, ArbitraryScaleFactor) {
+ // Do not test if the ImageSkia doesn't support arbitrary scale factors.
+ if (!ImageSkia::IsDSFScalingInImageSkiaEnabled())
+ return;
+
+ // source is owned by |image|
+ DynamicSource* source = new DynamicSource(Size(100, 200));
+ ImageSkia image(source, gfx::Size(100, 200));
+
+ image.GetRepresentation(1.5f);
+ EXPECT_EQ(2.0f, source->GetLastRequestedScaleAndReset());
+ std::vector<ImageSkiaRep> image_reps = image.image_reps();
+ EXPECT_EQ(2u, image_reps.size());
+
+ std::vector<float> scale_factors;
+ for (size_t i = 0; i < image_reps.size(); ++i) {
+ scale_factors.push_back(image_reps[i].scale());
+ }
+ std::sort(scale_factors.begin(), scale_factors.end());
+ EXPECT_EQ(1.5f, scale_factors[0]);
+ EXPECT_EQ(2.0f, scale_factors[1]);
+
+ // Requesting 1.75 scale factor also falls back to 2.0f and rescale.
+ // However, the image already has the 2.0f data, so it won't fetch again.
+ image.GetRepresentation(1.75f);
+ EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset());
+ image_reps = image.image_reps();
+ EXPECT_EQ(3u, image_reps.size());
+
+ scale_factors.clear();
+ for (size_t i = 0; i < image_reps.size(); ++i) {
+ scale_factors.push_back(image_reps[i].scale());
+ }
+ std::sort(scale_factors.begin(), scale_factors.end());
+ EXPECT_EQ(1.5f, scale_factors[0]);
+ EXPECT_EQ(1.75f, scale_factors[1]);
+ EXPECT_EQ(2.0f, scale_factors[2]);
+
+ // 1.25 is falled back to 1.0.
+ image.GetRepresentation(1.25f);
+ EXPECT_EQ(1.0f, source->GetLastRequestedScaleAndReset());
+ image_reps = image.image_reps();
+ EXPECT_EQ(5u, image_reps.size());
+
+ // Scale factor less than 1.0f will be falled back to 1.0f
+ image.GetRepresentation(0.75f);
+ EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset());
+ image_reps = image.image_reps();
+ EXPECT_EQ(6u, image_reps.size());
+
+ scale_factors.clear();
+ for (size_t i = 0; i < image_reps.size(); ++i) {
+ scale_factors.push_back(image_reps[i].scale());
+ }
+ std::sort(scale_factors.begin(), scale_factors.end());
+ EXPECT_EQ(0.75f, scale_factors[0]);
+ EXPECT_EQ(1.0f, scale_factors[1]);
+ EXPECT_EQ(1.25f, scale_factors[2]);
+ EXPECT_EQ(1.5f, scale_factors[3]);
+ EXPECT_EQ(1.75f, scale_factors[4]);
+ EXPECT_EQ(2.0f, scale_factors[5]);
+
+ // Scale factor greater than 2.0f is falled back to 2.0f because it's not
+ // supported.
+ image.GetRepresentation(3.0f);
+ EXPECT_EQ(0.0f, source->GetLastRequestedScaleAndReset());
+ image_reps = image.image_reps();
+ EXPECT_EQ(7u, image_reps.size());
+}
+
+TEST_F(ImageSkiaTest, ArbitraryScaleFactorWithMissingResource) {
+ // Do not test if the ImageSkia doesn't support arbitrary scale factors.
+ if (!ImageSkia::IsDSFScalingInImageSkiaEnabled())
+ return;
+
+ ImageSkia image(new FixedSource(
+ ImageSkiaRep(Size(100, 200), 1.0f)), Size(100, 200));
+
+ // Requesting 1.5f -- falls back to 2.0f, but couldn't find. It should
+ // look up 1.0f and then rescale it.
+ const ImageSkiaRep& rep = image.GetRepresentation(1.5f);
+ EXPECT_EQ(1.5f, rep.scale());
+ EXPECT_EQ(2U, image.image_reps().size());
+ EXPECT_EQ(1.0f, image.image_reps()[0].scale());
+ EXPECT_EQ(1.5f, image.image_reps()[1].scale());
+}
+
+TEST_F(ImageSkiaTest, UnscaledImageForArbitraryScaleFactor) {
+ // Do not test if the ImageSkia doesn't support arbitrary scale factors.
+ if (!ImageSkia::IsDSFScalingInImageSkiaEnabled())
+ return;
+
+ // 0.0f means unscaled.
+ ImageSkia image(new FixedSource(
+ ImageSkiaRep(Size(100, 200), 0.0f)), Size(100, 200));
+
+ // Requesting 2.0f, which should return 1.0f unscaled image.
+ const ImageSkiaRep& rep = image.GetRepresentation(2.0f);
+ EXPECT_EQ(1.0f, rep.scale());
+ EXPECT_EQ("100x200", rep.pixel_size().ToString());
+ EXPECT_TRUE(rep.unscaled());
+ EXPECT_EQ(1U, image.image_reps().size());
+
+ // Same for any other scale factors.
+ const ImageSkiaRep& rep15 = image.GetRepresentation(1.5f);
+ EXPECT_EQ(1.0f, rep15.scale());
+ EXPECT_EQ("100x200", rep15.pixel_size().ToString());
+ EXPECT_TRUE(rep15.unscaled());
+ EXPECT_EQ(1U, image.image_reps().size());
+
+ const ImageSkiaRep& rep12 = image.GetRepresentation(1.2f);
+ EXPECT_EQ(1.0f, rep12.scale());
+ EXPECT_EQ("100x200", rep12.pixel_size().ToString());
+ EXPECT_TRUE(rep12.unscaled());
+ EXPECT_EQ(1U, image.image_reps().size());
+}
+
} // namespace gfx
diff --git a/chromium/ui/gfx/image/image_skia_util_mac.h b/chromium/ui/gfx/image/image_skia_util_mac.h
index 553c3f8741d..fc6a65fb027 100644
--- a/chromium/ui/gfx/image/image_skia_util_mac.h
+++ b/chromium/ui/gfx/image/image_skia_util_mac.h
@@ -31,10 +31,6 @@ GFX_EXPORT gfx::ImageSkia ImageSkiaFromNSImage(NSImage* image);
GFX_EXPORT gfx::ImageSkia ImageSkiaFromResizedNSImage(NSImage* image,
NSSize size);
-// Resizes |[NSImage imageNamed:@NSApplicationIcon]| to have edge width of
-// |size| DIP and returns result as ImageSkia.
-GFX_EXPORT gfx::ImageSkia ApplicationIconAtSize(int size);
-
// Converts to NSImage from ImageSkia.
GFX_EXPORT NSImage* NSImageFromImageSkia(const gfx::ImageSkia& image_skia);
diff --git a/chromium/ui/gfx/image/image_skia_util_mac.mm b/chromium/ui/gfx/image/image_skia_util_mac.mm
index 281badc7423..26c067331a7 100644
--- a/chromium/ui/gfx/image/image_skia_util_mac.mm
+++ b/chromium/ui/gfx/image/image_skia_util_mac.mm
@@ -78,12 +78,6 @@ gfx::ImageSkia ImageSkiaFromResizedNSImage(NSImage* image,
return image_skia;
}
-gfx::ImageSkia ApplicationIconAtSize(int desired_size) {
- NSImage* image = [NSImage imageNamed:@"NSApplicationIcon"];
- return ImageSkiaFromResizedNSImage(image,
- NSMakeSize(desired_size, desired_size));
-}
-
NSImage* NSImageFromImageSkia(const gfx::ImageSkia& image_skia) {
if (image_skia.isNull())
return nil;
diff --git a/chromium/ui/gfx/image/image_unittest.cc b/chromium/ui/gfx/image/image_unittest.cc
index 039cb13f606..ca9efa0003c 100644
--- a/chromium/ui/gfx/image/image_unittest.cc
+++ b/chromium/ui/gfx/image/image_unittest.cc
@@ -10,10 +10,7 @@
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_unittest_util.h"
-#if defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
-#include "ui/gfx/gtk_util.h"
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
#include "base/mac/foundation_util.h"
#include "skia/ext/skia_utils_ios.h"
#elif defined(OS_MACOSX)
@@ -75,7 +72,7 @@ TEST_F(ImageTest, EmptyImage) {
// Test constructing a gfx::Image from an empty PlatformImage.
TEST_F(ImageTest, EmptyImageFromEmptyPlatformImage) {
-#if defined(OS_IOS) || defined(OS_MACOSX) || defined(TOOLKIT_GTK)
+#if defined(OS_IOS) || defined(OS_MACOSX)
gfx::Image image1(NULL);
EXPECT_TRUE(image1.IsEmpty());
EXPECT_EQ(0, image1.Width());
@@ -246,12 +243,24 @@ TEST_F(ImageTest, MultiResolutionPNGToImageSkia) {
scales.push_back(1.0f);
scales.push_back(2.0f);
gfx::ImageSkia image_skia = image.AsImageSkia();
- EXPECT_TRUE(gt::ImageSkiaStructureMatches(image_skia, kSize1x, kSize1x,
- scales));
EXPECT_TRUE(gt::IsEqual(bytes1x,
image_skia.GetRepresentation(1.0f).sk_bitmap()));
EXPECT_TRUE(gt::IsEqual(bytes2x,
image_skia.GetRepresentation(2.0f).sk_bitmap()));
+ EXPECT_TRUE(gt::ImageSkiaStructureMatches(image_skia, kSize1x, kSize1x,
+ scales));
+#if !defined(OS_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());
+ ASSERT_EQ(1.6f, rep_1_6x.scale());
+ EXPECT_EQ("40x40", rep_1_6x.pixel_size().ToString());
+
+ gfx::ImageSkiaRep rep_0_8x = image_skia.GetRepresentation(0.8f);
+ ASSERT_FALSE(rep_0_8x.is_null());
+ ASSERT_EQ(0.8f, rep_0_8x.scale());
+ EXPECT_EQ("20x20", rep_0_8x.pixel_size().ToString());
+#endif
}
TEST_F(ImageTest, MultiResolutionPNGToPlatform) {
@@ -436,27 +445,6 @@ TEST_F(ImageTest, PlatformToSkiaToCopy) {
delete bitmap;
}
-#if defined(TOOLKIT_GTK)
-TEST_F(ImageTest, SkiaToGdkCopy) {
- GdkPixbuf* pixbuf;
-
- {
- gfx::Image image(gt::CreateImageSkia(25, 25));
- pixbuf = image.CopyGdkPixbuf();
- }
-
- EXPECT_TRUE(pixbuf);
- g_object_unref(pixbuf);
-}
-
-TEST_F(ImageTest, SkiaToCairoCreatesGdk) {
- gfx::Image image(gt::CreateImageSkia(25, 25));
- EXPECT_FALSE(image.HasRepresentation(gfx::Image::kImageRepGdk));
- EXPECT_TRUE(image.ToCairo());
- EXPECT_TRUE(image.HasRepresentation(gfx::Image::kImageRepGdk));
-}
-#endif
-
#if defined(OS_IOS)
TEST_F(ImageTest, SkiaToCocoaTouchCopy) {
UIImage* ui_image;
@@ -495,9 +483,8 @@ TEST_F(ImageTest, SkBitmapConversionPreservesOrientation) {
const int width = 50;
const int height = 50;
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
- bitmap.allocPixels();
- bitmap.eraseRGB(0, 255, 0);
+ bitmap.allocN32Pixels(width, height);
+ bitmap.eraseARGB(255, 0, 255, 0);
// Paint the upper half of the image in red (lower half is in green).
SkCanvas canvas(bitmap);
@@ -538,9 +525,7 @@ TEST_F(ImageTest, SkBitmapConversionPreservesTransparency) {
const int width = 50;
const int height = 50;
SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0,
- kPremul_SkAlphaType);
- bitmap.allocPixels();
+ bitmap.allocN32Pixels(width, height);
bitmap.eraseARGB(0, 0, 255, 0);
// Paint the upper half of the image in red (lower half is transparent).
diff --git a/chromium/ui/gfx/image/image_unittest_util.cc b/chromium/ui/gfx/image/image_unittest_util.cc
index 4baf30a4cc6..e9a003216d9 100644
--- a/chromium/ui/gfx/image/image_unittest_util.cc
+++ b/chromium/ui/gfx/image/image_unittest_util.cc
@@ -15,10 +15,7 @@
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia.h"
-#if defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
-#include "ui/gfx/gtk_util.h"
-#elif defined(OS_IOS)
+#if defined(OS_IOS)
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "skia/ext/skia_utils_ios.h"
@@ -59,7 +56,7 @@ const SkBitmap CreateBitmap(int width, int height) {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
bitmap.allocPixels();
- bitmap.eraseRGB(0, 255, 0);
+ bitmap.eraseARGB(255, 0, 255, 0);
return bitmap;
}
@@ -83,6 +80,8 @@ gfx::Image CreateImage(int width, int height) {
}
bool IsEqual(const gfx::Image& img1, const gfx::Image& img2) {
+ img1.AsImageSkia().EnsureRepsForSupportedScales();
+ img2.AsImageSkia().EnsureRepsForSupportedScales();
std::vector<gfx::ImageSkiaRep> img1_reps = img1.AsImageSkia().image_reps();
gfx::ImageSkia image_skia2 = img2.AsImageSkia();
if (image_skia2.image_reps().size() != img1_reps.size())
@@ -192,8 +191,6 @@ PlatformImage CreatePlatformImage() {
NSImage* image = gfx::SkBitmapToNSImage(bitmap);
base::mac::NSObjectRetain(image);
return image;
-#elif defined(TOOLKIT_GTK)
- return gfx::GdkPixbufFromSkBitmap(bitmap);
#else
return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
#endif
@@ -204,8 +201,6 @@ gfx::Image::RepresentationType GetPlatformRepresentationType() {
return gfx::Image::kImageRepCocoaTouch;
#elif defined(OS_MACOSX)
return gfx::Image::kImageRepCocoa;
-#elif defined(TOOLKIT_GTK)
- return gfx::Image::kImageRepGdk;
#else
return gfx::Image::kImageRepSkia;
#endif
@@ -216,8 +211,6 @@ PlatformImage ToPlatformType(const gfx::Image& image) {
return image.ToUIImage();
#elif defined(OS_MACOSX)
return image.ToNSImage();
-#elif defined(TOOLKIT_GTK)
- return image.ToGdkPixbuf();
#else
return image.AsImageSkia();
#endif
@@ -228,8 +221,6 @@ PlatformImage CopyPlatformType(const gfx::Image& image) {
return image.CopyUIImage();
#elif defined(OS_MACOSX)
return image.CopyNSImage();
-#elif defined(TOOLKIT_GTK)
- return image.CopyGdkPixbuf();
#else
return image.AsImageSkia();
#endif
@@ -237,16 +228,6 @@ PlatformImage CopyPlatformType(const gfx::Image& image) {
#if defined(OS_MACOSX)
// Defined in image_unittest_util_mac.mm.
-#elif defined(TOOLKIT_GTK)
-SkColor GetPlatformImageColor(PlatformImage image, int x, int y) {
- int n_channels = gdk_pixbuf_get_n_channels(image);
- int rowstride = gdk_pixbuf_get_rowstride(image);
- guchar* gdk_pixels = gdk_pixbuf_get_pixels(image);
-
- guchar* pixel = gdk_pixels + (y * rowstride) + (x * n_channels);
- guchar alpha = gdk_pixbuf_get_has_alpha(image) ? pixel[3] : 255;
- return SkColorSetARGB(alpha, pixel[0], pixel[1], pixel[2]);
-}
#else
SkColor GetPlatformImageColor(PlatformImage image, int x, int y) {
SkBitmap bitmap = *image.bitmap();
@@ -264,7 +245,7 @@ void CheckIsTransparent(SkColor color) {
}
bool IsPlatformImageValid(PlatformImage image) {
-#if defined(OS_MACOSX) || defined(TOOLKIT_GTK)
+#if defined(OS_MACOSX)
return image != NULL;
#else
return !image.isNull();
@@ -272,7 +253,7 @@ bool IsPlatformImageValid(PlatformImage image) {
}
bool PlatformImagesEqual(PlatformImage image1, PlatformImage image2) {
-#if defined(OS_MACOSX) || defined(TOOLKIT_GTK)
+#if defined(OS_MACOSX)
return image1 == image2;
#else
return image1.BackedBySameObjectAs(image2);
diff --git a/chromium/ui/gfx/image/image_unittest_util.h b/chromium/ui/gfx/image/image_unittest_util.h
index 4788e4e1009..cac8015eb16 100644
--- a/chromium/ui/gfx/image/image_unittest_util.h
+++ b/chromium/ui/gfx/image/image_unittest_util.h
@@ -18,8 +18,6 @@ namespace test {
typedef UIImage* PlatformImage;
#elif defined(OS_MACOSX)
typedef NSImage* PlatformImage;
-#elif defined(TOOLKIT_GTK)
-typedef GdkPixbuf* PlatformImage;
#else
typedef gfx::ImageSkia PlatformImage;
#endif
diff --git a/chromium/ui/gfx/image/image_util.cc b/chromium/ui/gfx/image/image_util.cc
index 59d631d171d..89a3f8c03b8 100644
--- a/chromium/ui/gfx/image/image_util.cc
+++ b/chromium/ui/gfx/image/image_util.cc
@@ -12,6 +12,8 @@
namespace gfx {
+const uint32_t kMinimumVisibleOpacity = 12;
+
// The iOS implementations of the JPEG functions are in image_util_ios.mm.
#if !defined(OS_IOS)
Image ImageFrom1xJPEGEncodedData(const unsigned char* input,
@@ -24,7 +26,7 @@ Image ImageFrom1xJPEGEncodedData(const unsigned char* input,
}
bool JPEG1xEncodedDataFromImage(const Image& image, int quality,
- std::vector<unsigned char>* dst) {
+ std::vector<unsigned char>* dst) {
const gfx::ImageSkiaRep& image_skia_rep =
image.AsImageSkia().GetRepresentation(1.0f);
if (image_skia_rep.scale() != 1.0f)
@@ -45,4 +47,57 @@ bool JPEG1xEncodedDataFromImage(const Image& image, int quality,
}
#endif // !defined(OS_IOS)
+bool VisibleMargins(const ImageSkia& image, int* leading, int* trailing) {
+ *leading = 0;
+ *trailing = std::max(1, image.width()) - 1;
+ if (!image.HasRepresentation(1.0))
+ return false;
+
+ const ImageSkiaRep& rep = image.GetRepresentation(1.0);
+ if (rep.is_null())
+ return false;
+
+ const SkBitmap& bitmap = rep.sk_bitmap();
+ if (bitmap.isNull() || bitmap.width() == 0)
+ return false;
+
+ if (bitmap.isOpaque())
+ return true;
+
+ SkAutoLockPixels l(bitmap);
+ int inner_min = bitmap.width();
+ for (int x = 0; x < bitmap.width(); ++x) {
+ for (int y = 0; y < bitmap.height(); ++y) {
+ if (SkColorGetA(bitmap.getColor(x, y)) > kMinimumVisibleOpacity) {
+ inner_min = x;
+ break;
+ }
+ }
+ if (inner_min < bitmap.width())
+ break;
+ }
+
+ int inner_max = -1;
+ for (int x = bitmap.width() - 1; x > inner_min; --x) {
+ for (int y = 0; y < bitmap.height(); ++y) {
+ if (SkColorGetA(bitmap.getColor(x, y)) > kMinimumVisibleOpacity) {
+ inner_max = x;
+ break;
+ }
+ }
+ if (inner_max > -1)
+ break;
+ }
+
+ if (inner_min == bitmap.width()) {
+ *leading = bitmap.width()/2;
+ *trailing = bitmap.width()/2 + 1;
+ return true;
+ }
+
+ *leading = inner_min;
+ *trailing = inner_max;
+ return true;
}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/image/image_util.h b/chromium/ui/gfx/image/image_util.h
index f33835ca232..2711850dc96 100644
--- a/chromium/ui/gfx/image/image_util.h
+++ b/chromium/ui/gfx/image/image_util.h
@@ -12,6 +12,7 @@
namespace gfx {
class Image;
+class ImageSkia;
}
namespace gfx {
@@ -31,6 +32,22 @@ GFX_EXPORT bool JPEG1xEncodedDataFromImage(const Image& image,
int quality,
std::vector<unsigned char>* dst);
+// Returns the visible (non-transparent) width of the 1x rep of the given
+// image. If the image has no transparency, the leading value will be 0 and
+// the trailing will be the image width. Return values are in the 1x width
+// pixel units. Margins are given in 0-based column format. So if the image
+// has only transparent pixels in columns 0, 1, 2, 3, then the leading value
+// will be 4. Similarly, if there are all transparent pixels in column
+// width-2, width-1, then the trailing margin value will be width-3.
+// Returns true if the value is computed from opacity, false if it is a
+// default value because of null image, missing Rep, etc.
+// This method is only suitable for fairly small images (i.e. 16x16).
+// The margins for a completely transparent image will be w/2-1, w/2, but this
+// will be an expensive operation: it isn't expected that it will be frequently
+// calculated.
+GFX_EXPORT bool VisibleMargins(const ImageSkia& image,
+ int* leading, int* trailing);
+
} // namespace gfx
#endif // UI_GFX_IMAGE_IMAGE_UTIL_H_
diff --git a/chromium/ui/gfx/image/image_util_unittest.cc b/chromium/ui/gfx/image/image_util_unittest.cc
index cd9d74898f6..74c39e68fa4 100644
--- a/chromium/ui/gfx/image/image_util_unittest.cc
+++ b/chromium/ui/gfx/image/image_util_unittest.cc
@@ -9,6 +9,8 @@
#include "base/memory/scoped_ptr.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_unittest_util.h"
TEST(ImageUtilTest, JPEGEncodeAndDecode) {
@@ -23,3 +25,79 @@ TEST(ImageUtilTest, JPEGEncodeAndDecode) {
// JPEG is lossy, so simply check that the image decoded successfully.
EXPECT_FALSE(decoded.IsEmpty());
}
+
+TEST(ImageUtilTest, TestVisibleMargins) {
+ // Image with non-transparent piece should return margins at those
+ // columns.
+ SkBitmap bitmap1;
+ bitmap1.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ bitmap1.allocPixels();
+ bitmap1.eraseColor(SK_ColorTRANSPARENT);
+ bitmap1.eraseArea(SkIRect::MakeLTRB(3, 3, 14, 14), SK_ColorYELLOW);
+ gfx::ImageSkia img = gfx::ImageSkia::CreateFrom1xBitmap(bitmap1);
+ int x = 0;
+ int y = 0;
+ gfx::VisibleMargins(img, &x, &y);
+ EXPECT_EQ(3, x);
+ EXPECT_EQ(13, y);
+ EXPECT_EQ(16, img.width());
+
+ // Full-width-transparent image should return margins in the center
+ // of the image.
+ SkBitmap bitmap2;
+ bitmap2.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ bitmap2.allocPixels();
+ bitmap2.eraseColor(SK_ColorTRANSPARENT);
+ gfx::ImageSkia img_transparent = gfx::ImageSkia::CreateFrom1xBitmap(bitmap2);
+ x = 0;
+ y = 0;
+ gfx::VisibleMargins(img_transparent, &x, &y);
+ EXPECT_EQ(8, x);
+ EXPECT_EQ(9, y);
+ EXPECT_EQ(16, img_transparent.width());
+
+ // Image with non-transparent piece that is skewed to one side should
+ // return margins at those columns.
+ SkBitmap bitmap3;
+ bitmap3.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ bitmap3.allocPixels();
+ bitmap3.eraseColor(SK_ColorTRANSPARENT);
+ bitmap3.eraseArea(SkIRect::MakeLTRB(3, 3, 5, 5), SK_ColorYELLOW);
+ gfx::ImageSkia img3 = gfx::ImageSkia::CreateFrom1xBitmap(bitmap3);
+ x = 0;
+ y = 0;
+ gfx::VisibleMargins(img3, &x, &y);
+ EXPECT_EQ(3, x);
+ EXPECT_EQ(4, y);
+ EXPECT_EQ(16, img3.width());
+
+ // Image with non-transparent piece that is at one edge should
+ // return margins at those columns.
+ SkBitmap bitmap4;
+ bitmap4.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ bitmap4.allocPixels();
+ bitmap4.eraseColor(SK_ColorTRANSPARENT);
+ bitmap4.eraseArea(SkIRect::MakeLTRB(0, 3, 5, 5), SK_ColorYELLOW);
+ gfx::ImageSkia img4 = gfx::ImageSkia::CreateFrom1xBitmap(bitmap4);
+ x = 0;
+ y = 0;
+ gfx::VisibleMargins(img4, &x, &y);
+ EXPECT_EQ(0, x);
+ EXPECT_EQ(4, y);
+ EXPECT_EQ(16, img4.width());
+
+ // Image with non-transparent piece that is at trailing edge should
+ // return margins at those columns.
+ SkBitmap bitmap5;
+ bitmap5.setConfig(SkBitmap::kARGB_8888_Config, 16, 16);
+ bitmap5.allocPixels();
+ bitmap5.eraseColor(SK_ColorTRANSPARENT);
+ bitmap5.eraseArea(SkIRect::MakeLTRB(4, 3, 16, 16), SK_ColorYELLOW);
+ gfx::ImageSkia img5 = gfx::ImageSkia::CreateFrom1xBitmap(bitmap5);
+ x = 0;
+ y = 0;
+ gfx::VisibleMargins(img5, &x, &y);
+ EXPECT_EQ(4, x);
+ EXPECT_EQ(15, y);
+ EXPECT_EQ(16, img5.width());
+}
diff --git a/chromium/ui/gfx/insets.h b/chromium/ui/gfx/insets.h
index a419059a55d..aa4b9eb5270 100644
--- a/chromium/ui/gfx/insets.h
+++ b/chromium/ui/gfx/insets.h
@@ -1,52 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_INSETS_H_
-#define UI_GFX_INSETS_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/insets.h"
-#include <string>
-
-#include "build/build_config.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/insets_base.h"
-
-#if defined(TOOLKIT_GTK)
-typedef struct _GtkBorder GtkBorder;
-#endif
-
-namespace gfx {
-
-// An integer version of gfx::Insets.
-class GFX_EXPORT Insets : public InsetsBase<Insets, int> {
- public:
- Insets();
- Insets(int top, int left, int bottom, int right);
-#if defined(TOOLKIT_GTK)
- explicit Insets(const GtkBorder& border);
-#endif
-
- ~Insets();
-
- Insets Scale(float scale) const {
- return Scale(scale, scale);
- }
-
- Insets Scale(float x_scale, float y_scale) const {
- return Insets(static_cast<int>(top() * y_scale),
- static_cast<int>(left() * x_scale),
- static_cast<int>(bottom() * y_scale),
- static_cast<int>(right() * x_scale));
- }
-
- // Returns a string representation of the insets.
- std::string ToString() const;
-};
-
-#if !defined(COMPILER_MSVC)
-extern template class InsetsBase<Insets, int>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_INSETS_H_
diff --git a/chromium/ui/gfx/insets_f.h b/chromium/ui/gfx/insets_f.h
index 43b801dcb22..d6cfd0392af 100644
--- a/chromium/ui/gfx/insets_f.h
+++ b/chromium/ui/gfx/insets_f.h
@@ -1,33 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_INSETS_F_H_
-#define UI_GFX_INSETS_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/insets_f.h"
-#include <string>
-
-#include "build/build_config.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/insets_base.h"
-
-namespace gfx {
-
-// A floating versin of gfx::Insets.
-class GFX_EXPORT InsetsF : public InsetsBase<InsetsF, float> {
- public:
- InsetsF();
- InsetsF(float top, float left, float bottom, float right);
- ~InsetsF();
-
- // Returns a string representation of the insets.
- std::string ToString() const;
-};
-
-#if !defined(COMPILER_MSVC)
-extern template class InsetsBase<InsetsF, float>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_INSETS_F_H_
diff --git a/chromium/ui/gfx/linux_font_delegate.cc b/chromium/ui/gfx/linux_font_delegate.cc
new file mode 100644
index 00000000000..3dfdf942ece
--- /dev/null
+++ b/chromium/ui/gfx/linux_font_delegate.cc
@@ -0,0 +1,23 @@
+// 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/linux_font_delegate.h"
+
+namespace {
+
+gfx::LinuxFontDelegate* g_linux_font_delegate = 0;
+
+} // namespace
+
+namespace gfx {
+
+void LinuxFontDelegate::SetInstance(LinuxFontDelegate* instance) {
+ g_linux_font_delegate = instance;
+}
+
+const LinuxFontDelegate* LinuxFontDelegate::instance() {
+ return g_linux_font_delegate;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/linux_font_delegate.h b/chromium/ui/gfx/linux_font_delegate.h
new file mode 100644
index 00000000000..8a3070bfd7b
--- /dev/null
+++ b/chromium/ui/gfx/linux_font_delegate.h
@@ -0,0 +1,49 @@
+// 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_LINUX_FONT_DELEGATE_H_
+#define UI_GFX_LINUX_FONT_DELEGATE_H_
+
+#include <string>
+
+#include "ui/gfx/font_render_params_linux.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// Allows a Linux platform specific overriding of font preferences.
+class GFX_EXPORT LinuxFontDelegate {
+ public:
+ virtual ~LinuxFontDelegate() {}
+
+ // 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(LinuxFontDelegate* instance);
+
+ // Returns a LinuxFontDelegate 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 LinuxFontDelegate* instance();
+
+ // Whether we should antialias our text.
+ virtual bool UseAntialiasing() const = 0;
+
+ // What sort of text hinting should we apply?
+ virtual FontRenderParams::Hinting GetHintingStyle() const = 0;
+
+ // What sort of subpixel rendering should we perform.
+ virtual FontRenderParams::SubpixelRendering
+ GetSubpixelRenderingStyle() const = 0;
+
+ // Returns the default font name for pango style rendering. The format is a
+ // string of the form "[font name] [font size]".
+ virtual std::string GetDefaultFontName() const = 0;
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_LINUX_FONT_DELEGATE_H_
diff --git a/chromium/ui/gfx/matrix3_f.h b/chromium/ui/gfx/matrix3_f.h
index a8ae5b578a8..936c312475b 100644
--- a/chromium/ui/gfx/matrix3_f.h
+++ b/chromium/ui/gfx/matrix3_f.h
@@ -1,108 +1,7 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// 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_MATRIX3_F_H_
-#define UI_GFX_MATRIX3_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/matrix3_f.h"
-#include "base/logging.h"
-#include "ui/gfx/vector3d_f.h"
-
-namespace gfx {
-
-class GFX_EXPORT Matrix3F {
- public:
- ~Matrix3F();
-
- static Matrix3F Zeros();
- static Matrix3F Ones();
- static Matrix3F Identity();
- static Matrix3F FromOuterProduct(const Vector3dF& a, const Vector3dF& bt);
-
- bool IsEqual(const Matrix3F& rhs) const;
-
- // Element-wise comparison with given precision.
- bool IsNear(const Matrix3F& rhs, float precision) const;
-
- float get(int i, int j) const {
- return data_[MatrixToArrayCoords(i, j)];
- }
-
- void set(int i, int j, float v) {
- data_[MatrixToArrayCoords(i, j)] = v;
- }
-
- void set(float m00, float m01, float m02,
- float m10, float m11, float m12,
- float m20, float m21, float m22) {
- data_[0] = m00;
- data_[1] = m01;
- data_[2] = m02;
- data_[3] = m10;
- data_[4] = m11;
- data_[5] = m12;
- data_[6] = m20;
- data_[7] = m21;
- data_[8] = m22;
- }
-
- Vector3dF get_column(int i) const {
- return Vector3dF(
- data_[MatrixToArrayCoords(0, i)],
- data_[MatrixToArrayCoords(1, i)],
- data_[MatrixToArrayCoords(2, i)]);
- }
-
- void set_column(int i, const Vector3dF& c) {
- data_[MatrixToArrayCoords(0, i)] = c.x();
- data_[MatrixToArrayCoords(1, i)] = c.y();
- data_[MatrixToArrayCoords(2, i)] = c.z();
- }
-
- // Returns an inverse of this if the matrix is non-singular, zero (== Zero())
- // otherwise.
- Matrix3F Inverse() const;
-
- // Value of the determinant of the matrix.
- float Determinant() const;
-
- // Trace (sum of diagonal elements) of the matrix.
- float Trace() const {
- return data_[MatrixToArrayCoords(0, 0)] +
- data_[MatrixToArrayCoords(1, 1)] +
- data_[MatrixToArrayCoords(2, 2)];
- }
-
- // Compute eigenvalues and (optionally) normalized eigenvectors of
- // a positive defnite matrix *this. Eigenvectors are computed only if
- // non-null |eigenvectors| matrix is passed. If it is NULL, the routine
- // will not attempt to compute eigenvectors but will still return eigenvalues
- // if they can be computed.
- // If eigenvalues cannot be computed (the matrix does not meet constraints)
- // the 0-vector is returned. Note that to retrieve eigenvalues, the matrix
- // only needs to be symmetric while eigenvectors require it to be
- // positive-definite. Passing a non-positive definite matrix will result in
- // NaNs in vectors which cannot be computed.
- // Eigenvectors are placed as column in |eigenvectors| in order corresponding
- // to eigenvalues.
- Vector3dF SolveEigenproblem(Matrix3F* eigenvectors) const;
-
- private:
- Matrix3F(); // Uninitialized default.
-
- static int MatrixToArrayCoords(int i, int j) {
- DCHECK(i >= 0 && i < 3);
- DCHECK(j >= 0 && j < 3);
- return i * 3 + j;
- }
-
- float data_[9];
-};
-
-inline bool operator==(const Matrix3F& lhs, const Matrix3F& rhs) {
- return lhs.IsEqual(rhs);
-}
-
-} // namespace gfx
-
-#endif // UI_GFX_MATRIX3_F_H_
diff --git a/chromium/ui/gfx/native_widget_types.h b/chromium/ui/gfx/native_widget_types.h
index bd14ed50f77..f7f2808cba9 100644
--- a/chromium/ui/gfx/native_widget_types.h
+++ b/chromium/ui/gfx/native_widget_types.h
@@ -98,14 +98,7 @@ typedef struct _PangoFontDescription PangoFontDescription;
typedef struct _cairo cairo_t;
#endif
-#if defined(TOOLKIT_GTK)
-typedef struct _GdkCursor GdkCursor;
-typedef union _GdkEvent GdkEvent;
-typedef struct _GdkPixbuf GdkPixbuf;
-typedef struct _GdkRegion GdkRegion;
-typedef struct _GtkWidget GtkWidget;
-typedef struct _GtkWindow GtkWindow;
-#elif defined(OS_ANDROID)
+#if defined(OS_ANDROID)
struct ANativeWindow;
namespace ui {
class WindowAndroid;
@@ -122,12 +115,6 @@ typedef aura::Window* NativeView;
typedef aura::Window* NativeWindow;
typedef SkRegion* NativeRegion;
typedef ui::Event* NativeEvent;
-#elif defined(OS_WIN)
-typedef HCURSOR NativeCursor;
-typedef HWND NativeView;
-typedef HWND NativeWindow;
-typedef HRGN NativeRegion;
-typedef MSG NativeEvent;
#elif defined(OS_IOS)
typedef void* NativeCursor;
typedef UIView* NativeView;
@@ -137,13 +124,8 @@ typedef UIEvent* NativeEvent;
typedef NSCursor* NativeCursor;
typedef NSView* NativeView;
typedef NSWindow* NativeWindow;
+typedef void* NativeRegion;
typedef NSEvent* NativeEvent;
-#elif defined(TOOLKIT_GTK)
-typedef GdkCursor* NativeCursor;
-typedef GtkWidget* NativeView;
-typedef GtkWindow* NativeWindow;
-typedef GdkRegion* NativeRegion;
-typedef GdkEvent* NativeEvent;
#elif defined(OS_ANDROID)
typedef void* NativeCursor;
typedef ui::ViewAndroid* NativeView;
@@ -166,11 +148,6 @@ typedef NSFont* NativeFont;
typedef NSTextField* NativeEditView;
typedef CGContext* NativeDrawingContext;
typedef void* NativeViewAccessible;
-#elif defined(TOOLKIT_GTK)
-typedef PangoFontDescription* NativeFont;
-typedef GtkWidget* NativeEditView;
-typedef cairo_t* NativeDrawingContext;
-typedef void* NativeViewAccessible;
#elif defined(USE_CAIRO)
typedef PangoFontDescription* NativeFont;
typedef void* NativeEditView;
@@ -194,8 +171,6 @@ const gfx::NativeCursor kNullCursor = static_cast<gfx::NativeCursor>(NULL);
typedef UIImage NativeImageType;
#elif defined(OS_MACOSX)
typedef NSImage NativeImageType;
-#elif defined(TOOLKIT_GTK)
-typedef GdkPixbuf NativeImageType;
#else
typedef SkBitmap NativeImageType;
#endif
@@ -208,32 +183,8 @@ typedef NativeImageType* NativeImage;
// See comment at the top of the file for usage.
typedef intptr_t NativeViewId;
-#if defined(OS_WIN) && !defined(USE_AURA)
-// Convert a NativeViewId to a NativeView.
-//
-// On Windows, we pass an HWND into the renderer. As stated above, the renderer
-// should not be performing operations on the view.
-static inline NativeView NativeViewFromId(NativeViewId id) {
- return reinterpret_cast<NativeView>(id);
-}
-#define NativeViewFromIdInBrowser(x) NativeViewFromId(x)
-#elif defined(OS_POSIX) || defined(USE_AURA)
-// On Mac, Linux and USE_AURA, a NativeView is a pointer to an object, and is
-// useless outside the process in which it was created. NativeViewFromId should
-// only be used inside the appropriate platform ifdef outside of the browser.
-// (NativeViewFromIdInBrowser can be used everywhere in the browser.) If your
-// cross-platform design involves a call to NativeViewFromId from outside the
-// browser it will never work on Mac or Linux and is fundamentally broken.
-
-// Please do not call this from outside the browser. It won't work; the name
-// should give you a subtle hint.
-static inline NativeView NativeViewFromIdInBrowser(NativeViewId id) {
- return reinterpret_cast<NativeView>(id);
-}
-#endif // defined(OS_POSIX)
-
// PluginWindowHandle is an abstraction wrapping "the types of windows
-// used by NPAPI plugins". On Windows it's an HWND, on X it's an X
+// used by NPAPI plugins". On Windows it's an HWND, on X it's an X
// window id.
#if defined(OS_WIN)
typedef HWND PluginWindowHandle;
@@ -241,11 +192,6 @@ static inline NativeView NativeViewFromIdInBrowser(NativeViewId id) {
#elif defined(USE_X11)
typedef unsigned long PluginWindowHandle;
const PluginWindowHandle kNullPluginWindow = 0;
-#elif defined(USE_AURA) && defined(OS_MACOSX)
- // Mac-Aura uses NSView-backed GLSurface. Regular Mac does not.
- // TODO(dhollowa): Rationalize these two definitions. http://crbug.com/104551.
- typedef NSView* PluginWindowHandle;
- const PluginWindowHandle kNullPluginWindow = 0;
#elif defined(OS_ANDROID)
typedef uint64 PluginWindowHandle;
const PluginWindowHandle kNullPluginWindow = 0;
@@ -253,17 +199,9 @@ static inline NativeView NativeViewFromIdInBrowser(NativeViewId id) {
typedef intptr_t PluginWindowHandle;
const PluginWindowHandle kNullPluginWindow = 0;
#else
- // On OS X we don't have windowed plugins.
- // We use a NULL/0 PluginWindowHandle in shared code to indicate there
- // is no window present, so mirror that behavior here.
- //
- // The GPU plugin is currently an exception to this rule. As of this
- // writing it uses some NPAPI infrastructure, and minimally we need
- // to identify the plugin instance via this window handle. When the
- // GPU plugin becomes a full-on GPU process, this typedef can be
- // returned to a bool. For now we use a type large enough to hold a
- // pointer on 64-bit architectures in case we need this capability.
- typedef uint64 PluginWindowHandle;
+ // On Mac we don't have windowed plugins. We use a NULL/0 PluginWindowHandle
+ // in shared code to indicate there is no window present.
+ typedef bool PluginWindowHandle;
const PluginWindowHandle kNullPluginWindow = 0;
#endif
@@ -271,20 +209,19 @@ enum SurfaceType {
EMPTY,
NATIVE_DIRECT,
NATIVE_TRANSPORT,
- TEXTURE_TRANSPORT
+ TEXTURE_TRANSPORT,
+ SURFACE_TYPE_LAST = TEXTURE_TRANSPORT
};
struct GLSurfaceHandle {
GLSurfaceHandle()
: handle(kNullPluginWindow),
transport_type(EMPTY),
- parent_gpu_process_id(0),
parent_client_id(0) {
}
GLSurfaceHandle(PluginWindowHandle handle_, SurfaceType transport_)
: handle(handle_),
transport_type(transport_),
- parent_gpu_process_id(0),
parent_client_id(0) {
DCHECK(!is_null() || handle == kNullPluginWindow);
DCHECK(transport_type != TEXTURE_TRANSPORT ||
@@ -297,7 +234,6 @@ struct GLSurfaceHandle {
}
PluginWindowHandle handle;
SurfaceType transport_type;
- int parent_gpu_process_id;
uint32 parent_client_id;
};
diff --git a/chromium/ui/gfx/nine_image_painter.cc b/chromium/ui/gfx/nine_image_painter.cc
new file mode 100644
index 00000000000..24a3e3b3627
--- /dev/null
+++ b/chromium/ui/gfx/nine_image_painter.cc
@@ -0,0 +1,157 @@
+// 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/nine_image_painter.h"
+
+#include <limits>
+
+#include "third_party/skia/include/core/SkPaint.h"
+#include "third_party/skia/include/core/SkRect.h"
+#include "third_party/skia/include/core/SkScalar.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/geometry/rect_conversions.h"
+#include "ui/gfx/geometry/safe_integer_conversions.h"
+#include "ui/gfx/image/image_skia_operations.h"
+#include "ui/gfx/insets.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/scoped_canvas.h"
+#include "ui/gfx/skia_util.h"
+
+namespace gfx {
+
+namespace {
+
+// The following functions width and height of the image in pixels for the
+// scale factor in the Canvas.
+int ImageWidthInPixels(const ImageSkia& i, Canvas* c) {
+ return i.GetRepresentation(c->image_scale()).pixel_width();
+}
+
+int ImageHeightInPixels(const ImageSkia& i, Canvas* c) {
+ return i.GetRepresentation(c->image_scale()).pixel_height();
+}
+
+// Stretches the given image over the specified canvas area.
+void Fill(Canvas* c,
+ const ImageSkia& i,
+ int x,
+ int y,
+ int w,
+ int h,
+ const SkPaint& paint) {
+ c->DrawImageIntInPixel(i, 0, 0, ImageWidthInPixels(i, c),
+ ImageHeightInPixels(i, c), x, y, w, h, false, paint);
+}
+
+} // namespace
+
+NineImagePainter::NineImagePainter(const std::vector<ImageSkia>& images) {
+ DCHECK_EQ(arraysize(images_), images.size());
+ for (size_t i = 0; i < arraysize(images_); ++i)
+ images_[i] = images[i];
+}
+
+NineImagePainter::NineImagePainter(const ImageSkia& image,
+ const Insets& insets) {
+ DCHECK_GE(image.width(), insets.width());
+ DCHECK_GE(image.height(), insets.height());
+
+ // Extract subsets of the original image to match the |images_| format.
+ const int x[] =
+ { 0, insets.left(), image.width() - insets.right(), image.width() };
+ const int y[] =
+ { 0, insets.top(), image.height() - insets.bottom(), image.height() };
+
+ for (size_t j = 0; j < 3; ++j) {
+ for (size_t i = 0; i < 3; ++i) {
+ images_[i + j * 3] = ImageSkiaOperations::ExtractSubset(image,
+ Rect(x[i], y[j], x[i + 1] - x[i], y[j + 1] - y[j]));
+ }
+ }
+}
+
+NineImagePainter::~NineImagePainter() {
+}
+
+bool NineImagePainter::IsEmpty() const {
+ return images_[0].isNull();
+}
+
+Size NineImagePainter::GetMinimumSize() const {
+ return IsEmpty() ? Size() : Size(
+ images_[0].width() + images_[1].width() + images_[2].width(),
+ images_[0].height() + images_[3].height() + images_[6].height());
+}
+
+void NineImagePainter::Paint(Canvas* canvas, const Rect& bounds) {
+ // When no alpha value is specified, use default value of 100% opacity.
+ Paint(canvas, bounds, std::numeric_limits<uint8>::max());
+}
+
+void NineImagePainter::Paint(Canvas* canvas,
+ const Rect& bounds,
+ const uint8 alpha) {
+ if (IsEmpty())
+ return;
+
+ ScopedCanvas scoped_canvas(canvas);
+ canvas->Translate(bounds.OffsetFromOrigin());
+
+ SkPaint paint;
+ paint.setAlpha(alpha);
+
+ // Get the current transform from the canvas and apply it to the logical
+ // bounds passed in. This will give us the pixel bounds which can be used
+ // to draw the images at the correct locations.
+ // We should not scale the bounds by the canvas->image_scale() as that can be
+ // different from the real scale in the canvas transform.
+ SkMatrix matrix = canvas->sk_canvas()->getTotalMatrix();
+ SkRect scaled_rect;
+ matrix.mapRect(&scaled_rect, RectToSkRect(bounds));
+
+ int scaled_width = gfx::ToCeiledInt(SkScalarToFloat(scaled_rect.width()));
+ int scaled_height = gfx::ToCeiledInt(SkScalarToFloat(scaled_rect.height()));
+
+ // In case the corners and edges don't all have the same width/height, we draw
+ // the center first, and extend it out in all directions to the edges of the
+ // images with the smallest widths/heights. This way there will be no
+ // unpainted areas, though some corners or edges might overlap the center.
+ int i0w = ImageWidthInPixels(images_[0], canvas);
+ int i2w = ImageWidthInPixels(images_[2], canvas);
+ int i3w = ImageWidthInPixels(images_[3], canvas);
+ int i5w = ImageWidthInPixels(images_[5], canvas);
+ int i6w = ImageWidthInPixels(images_[6], canvas);
+ int i8w = ImageWidthInPixels(images_[8], canvas);
+
+ int i4x = std::min(std::min(i0w, i3w), i6w);
+ int i4w = scaled_width - i4x - std::min(std::min(i2w, i5w), i8w);
+
+ int i0h = ImageHeightInPixels(images_[0], canvas);
+ int i1h = ImageHeightInPixels(images_[1], canvas);
+ int i2h = ImageHeightInPixels(images_[2], canvas);
+ int i6h = ImageHeightInPixels(images_[6], canvas);
+ int i7h = ImageHeightInPixels(images_[7], canvas);
+ int i8h = ImageHeightInPixels(images_[8], canvas);
+
+ int i4y = std::min(std::min(i0h, i1h), i2h);
+ int i4h = scaled_height - i4y - std::min(std::min(i6h, i7h), i8h);
+ if (!images_[4].isNull())
+ Fill(canvas, images_[4], i4x, i4y, i4w, i4h, paint);
+ canvas->DrawImageIntInPixel(images_[0], 0, 0, i0w, i0h,
+ 0, 0, i0w, i0h, false, paint);
+ Fill(canvas, images_[1], i0w, 0, scaled_width - i0w - i2w, i1h, paint);
+ canvas->DrawImageIntInPixel(images_[2], 0, 0, i2w, i2h, scaled_width - i2w,
+ 0, i2w, i2h, false, paint);
+ Fill(canvas, images_[3], 0, i0h, i3w, scaled_height - i0h - i6h, paint);
+ Fill(canvas, images_[5], scaled_width - i5w, i2h, i5w,
+ scaled_height - i2h - i8h, paint);
+ canvas->DrawImageIntInPixel(images_[6], 0, 0, i6w, i6h, 0,
+ scaled_height - i6h, i6w, i6h, false, paint);
+ Fill(canvas, images_[7], i6w, scaled_height - i7h, scaled_width - i6w - i8w,
+ i7h, paint);
+ canvas->DrawImageIntInPixel(images_[8], 0, 0, i8w, i8h, scaled_width - i8w,
+ scaled_height - i8h, i8w, i8h, false, paint);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/nine_image_painter.h b/chromium/ui/gfx/nine_image_painter.h
new file mode 100644
index 00000000000..46458d5cb28
--- /dev/null
+++ b/chromium/ui/gfx/nine_image_painter.h
@@ -0,0 +1,42 @@
+// 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_NINE_IMAGE_PAINTER_H_
+#define UI_GFX_NINE_IMAGE_PAINTER_H_
+
+#include "base/logging.h"
+#include "ui/gfx/gfx_export.h"
+#include "ui/gfx/image/image_skia.h"
+
+namespace gfx {
+
+class Canvas;
+class Insets;
+class Rect;
+
+class GFX_EXPORT NineImagePainter {
+ public:
+ explicit NineImagePainter(const std::vector<ImageSkia>& images);
+ NineImagePainter(const ImageSkia& image, const Insets& insets);
+ ~NineImagePainter();
+
+ bool IsEmpty() const;
+ Size GetMinimumSize() const;
+ void Paint(Canvas* canvas, const Rect& bounds);
+ void Paint(Canvas* canvas, const Rect& bounds, uint8 alpha);
+
+ private:
+ // Images are numbered as depicted below.
+ // ____________________
+ // |__i0__|__i1__|__i2__|
+ // |__i3__|__i4__|__i5__|
+ // |__i6__|__i7__|__i8__|
+ ImageSkia images_[9];
+
+ DISALLOW_COPY_AND_ASSIGN(NineImagePainter);
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_NINE_IMAGE_PAINTER_H_
diff --git a/chromium/ui/gfx/overlay_transform.h b/chromium/ui/gfx/overlay_transform.h
new file mode 100644
index 00000000000..1e27010933e
--- /dev/null
+++ b/chromium/ui/gfx/overlay_transform.h
@@ -0,0 +1,24 @@
+// 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_OVERLAY_TRANSFORM_H_
+#define UI_GFX_OVERLAY_TRANSFORM_H_
+
+namespace gfx {
+
+// Describes transformation to be applied to the buffer before presenting
+// to screen.
+enum OverlayTransform {
+ OVERLAY_TRANSFORM_INVALID,
+ OVERLAY_TRANSFORM_NONE,
+ OVERLAY_TRANSFORM_FLIP_HORIZONTAL,
+ OVERLAY_TRANSFORM_FLIP_VERTICAL,
+ OVERLAY_TRANSFORM_ROTATE_90,
+ OVERLAY_TRANSFORM_ROTATE_180,
+ OVERLAY_TRANSFORM_ROTATE_270,
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_OVERLAY_TRANSFORM_H_
diff --git a/chromium/ui/gfx/ozone/OWNERS b/chromium/ui/gfx/ozone/OWNERS
deleted file mode 100644
index 77f21b5cae7..00000000000
--- a/chromium/ui/gfx/ozone/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-rjkroege@chromium.org
diff --git a/chromium/ui/gfx/ozone/dri/dri_skbitmap.cc b/chromium/ui/gfx/ozone/dri/dri_skbitmap.cc
deleted file mode 100644
index 4fbe0f54d89..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_skbitmap.cc
+++ /dev/null
@@ -1,208 +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/ozone/dri/dri_skbitmap.h"
-
-#include <errno.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <xf86drm.h>
-
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "third_party/skia/include/core/SkPixelRef.h"
-
-namespace gfx {
-
-namespace {
-
-void DestroyDumbBuffer(int fd, uint32_t handle) {
- struct drm_mode_destroy_dumb destroy_request;
- destroy_request.handle = handle;
- drmIoctl(fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_request);
-}
-
-// Special DRM implementation of a SkPixelRef. The DRM allocator will create a
-// SkPixelRef for the backing pixels. It will then associate the SkPixelRef with
-// the SkBitmap. SkBitmap will access the allocated memory by locking the pixels
-// in the SkPixelRef.
-// At the end of its life the SkPixelRef is responsible for deallocating the
-// pixel memory.
-class DriSkPixelRef : public SkPixelRef {
- public:
- DriSkPixelRef(void* pixels,
- SkColorTable* color_table_,
- size_t size,
- int fd,
- uint32_t handle);
- virtual ~DriSkPixelRef();
-
- virtual void* onLockPixels(SkColorTable** ct) OVERRIDE;
- virtual void onUnlockPixels() OVERRIDE;
-
- SK_DECLARE_UNFLATTENABLE_OBJECT()
- private:
- // Raw pointer to the pixel memory.
- void* pixels_;
-
- // Optional color table associated with the pixel memory.
- SkColorTable* color_table_;
-
- // Size of the allocated memory.
- size_t size_;
-
- // File descriptor to the graphics card used to allocate/deallocate the
- // memory.
- int fd_;
-
- // Handle for the allocated memory.
- uint32_t handle_;
-
- DISALLOW_COPY_AND_ASSIGN(DriSkPixelRef);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// DriSkPixelRef implementation
-
-DriSkPixelRef::DriSkPixelRef(
- void* pixels,
- SkColorTable* color_table,
- size_t size,
- int fd,
- uint32_t handle)
- : pixels_(pixels),
- color_table_(color_table),
- size_(size),
- fd_(fd),
- handle_(handle) {
-}
-
-DriSkPixelRef::~DriSkPixelRef() {
- munmap(pixels_, size_);
- DestroyDumbBuffer(fd_, handle_);
-}
-
-void* DriSkPixelRef::onLockPixels(SkColorTable** ct) {
- *ct = color_table_;
- return pixels_;
-}
-
-void DriSkPixelRef::onUnlockPixels() {
-}
-
-} // namespace
-
-// Allocates pixel memory for a SkBitmap using DRM dumb buffers.
-class DriAllocator : public SkBitmap::Allocator {
- public:
- DriAllocator();
-
- virtual bool allocPixelRef(SkBitmap* bitmap,
- SkColorTable* color_table) OVERRIDE;
-
- private:
- bool AllocatePixels(DriSkBitmap* bitmap, SkColorTable* color_table);
-
- DISALLOW_COPY_AND_ASSIGN(DriAllocator);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// DriAllocator implementation
-
-DriAllocator::DriAllocator() {
-}
-
-bool DriAllocator::allocPixelRef(SkBitmap* bitmap,
- SkColorTable* color_table) {
- return AllocatePixels(static_cast<DriSkBitmap*>(bitmap), color_table);
-}
-
-bool DriAllocator::AllocatePixels(DriSkBitmap* bitmap,
- SkColorTable* color_table) {
- struct drm_mode_create_dumb request;
- request.width = bitmap->width();
- request.height = bitmap->height();
- request.bpp = bitmap->bytesPerPixel() << 3;
- request.flags = 0;
-
- if (drmIoctl(bitmap->get_fd(), DRM_IOCTL_MODE_CREATE_DUMB, &request) < 0) {
- DLOG(ERROR) << "Cannot create dumb buffer (" << errno << ") "
- << strerror(errno);
- return false;
- }
-
- CHECK(request.size == bitmap->getSize());
-
- bitmap->set_handle(request.handle);
-
- struct drm_mode_map_dumb map_request;
- map_request.handle = bitmap->get_handle();
- if (drmIoctl(bitmap->get_fd(), DRM_IOCTL_MODE_MAP_DUMB, &map_request)) {
- DLOG(ERROR) << "Cannot prepare dumb buffer for mapping (" << errno << ") "
- << strerror(errno);
- DestroyDumbBuffer(bitmap->get_fd(), bitmap->get_handle());
- return false;
- }
-
- void* pixels = mmap(0,
- bitmap->getSize(),
- PROT_READ | PROT_WRITE,
- MAP_SHARED,
- bitmap->get_fd(),
- map_request.offset);
- if (pixels == MAP_FAILED) {
- DLOG(ERROR) << "Cannot mmap dumb buffer (" << errno << ") "
- << strerror(errno);
- DestroyDumbBuffer(bitmap->get_fd(), bitmap->get_handle());
- return false;
- }
-
- bitmap->setPixelRef(new DriSkPixelRef(
- pixels,
- color_table,
- bitmap->getSize(),
- bitmap->get_fd(),
- bitmap->get_handle()))->unref();
- bitmap->lockPixels();
-
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DriSkBitmap implementation
-
-DriSkBitmap::DriSkBitmap(int fd)
- : fd_(fd),
- handle_(0),
- framebuffer_(0) {
-}
-
-DriSkBitmap::~DriSkBitmap() {
-}
-
-bool DriSkBitmap::Initialize() {
- DriAllocator drm_allocator;
- return allocPixels(&drm_allocator, NULL);
-}
-
-uint8_t DriSkBitmap::GetColorDepth() const {
- switch (config()) {
- case SkBitmap::kNo_Config:
- case SkBitmap::kA8_Config:
- return 0;
- case SkBitmap::kIndex8_Config:
- return 8;
- case SkBitmap::kRGB_565_Config:
- return 16;
- case SkBitmap::kARGB_4444_Config:
- return 12;
- case SkBitmap::kARGB_8888_Config:
- return 24;
- default:
- NOTREACHED();
- return 0;
- }
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/dri/dri_skbitmap.h b/chromium/ui/gfx/ozone/dri/dri_skbitmap.h
deleted file mode 100644
index f5b8f9455fa..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_skbitmap.h
+++ /dev/null
@@ -1,57 +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_OZONE_DRI_DRI_SKBITMAP_H_
-#define UI_GFX_OZONE_DRI_DRI_SKBITMAP_H_
-
-#include "base/basictypes.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/gfx/gfx_export.h"
-
-namespace gfx {
-
-// Extend the SkBitmap interface to keep track of additional parameters used by
-// the DRM stack when allocating buffers.
-class GFX_EXPORT DriSkBitmap : public SkBitmap {
- public:
- DriSkBitmap(int fd);
- virtual ~DriSkBitmap();
-
- // Allocates the backing pixels using DRI.
- // Return true on success, false otherwise.
- virtual bool Initialize();
-
- uint32_t get_handle() const { return handle_; };
-
- uint32_t get_framebuffer() const { return framebuffer_; };
-
- int get_fd() const { return fd_; };
-
- // Return the color depth of a pixel in this buffer.
- uint8_t GetColorDepth() const;
-
- private:
- friend class DriAllocator;
- friend class HardwareDisplayController;
-
- void set_handle(uint32_t handle) { handle_ = handle; };
- void set_framebuffer(uint32_t framebuffer) { framebuffer_ = framebuffer; };
-
- // File descriptor used by the DRI allocator to request buffers from the DRI
- // stack.
- int fd_;
-
- // Buffer handle used by the DRI allocator.
- uint32_t handle_;
-
- // Buffer ID used by the DRI modesettings API. This is set when the buffer is
- // registered with the CRTC.
- uint32_t framebuffer_;
-
- DISALLOW_COPY_AND_ASSIGN(DriSkBitmap);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_DRI_DRI_SKBITMAP_H_
diff --git a/chromium/ui/gfx/ozone/dri/dri_surface.cc b/chromium/ui/gfx/ozone/dri/dri_surface.cc
deleted file mode 100644
index c9b6af4b562..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_surface.cc
+++ /dev/null
@@ -1,113 +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/ozone/dri/dri_surface.h"
-
-#include <errno.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <xf86drm.h>
-
-#include "base/logging.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkBitmapDevice.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "ui/gfx/ozone/dri/dri_skbitmap.h"
-#include "ui/gfx/ozone/dri/hardware_display_controller.h"
-#include "ui/gfx/skia_util.h"
-
-namespace gfx {
-
-namespace {
-
-// Extends the SkBitmapDevice to allow setting the SkPixelRef. We use the setter
-// to change the SkPixelRef such that the device always points to the
-// backbuffer.
-class CustomSkBitmapDevice : public SkBitmapDevice {
- public:
- CustomSkBitmapDevice(const SkBitmap& bitmap) : SkBitmapDevice(bitmap) {}
- virtual ~CustomSkBitmapDevice() {}
-
- void SetPixelRef(SkPixelRef* pixel_ref) { setPixelRef(pixel_ref, 0); }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(CustomSkBitmapDevice);
-};
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////
-// DriSurface implementation
-
-DriSurface::DriSurface(
- HardwareDisplayController* controller)
- : controller_(controller),
- bitmaps_(),
- front_buffer_(0) {
-}
-
-DriSurface::~DriSurface() {
-}
-
-bool DriSurface::Initialize() {
- for (int i = 0; i < 2; ++i) {
- bitmaps_[i].reset(CreateBuffer());
- // TODO(dnicoara) Should select the configuration based on what the
- // underlying system supports.
- bitmaps_[i]->setConfig(SkBitmap::kARGB_8888_Config,
- controller_->get_mode().hdisplay,
- controller_->get_mode().vdisplay);
-
- if (!bitmaps_[i]->Initialize()) {
- return false;
- }
- }
-
- skia_device_ = skia::AdoptRef(
- new CustomSkBitmapDevice(*bitmaps_[front_buffer_ ^ 1].get()));
- skia_canvas_ = skia::AdoptRef(new SkCanvas(skia_device_.get()));
-
- return true;
-}
-
-uint32_t DriSurface::GetFramebufferId() const {
- CHECK(bitmaps_[0].get() && bitmaps_[1].get());
- return bitmaps_[front_buffer_ ^ 1]->get_framebuffer();
-}
-
-// This call is made after the hardware just started displaying our back buffer.
-// We need to update our pointer reference and synchronize the two buffers.
-void DriSurface::SwapBuffers() {
- CHECK(bitmaps_[0].get() && bitmaps_[1].get());
-
- // Update our front buffer pointer.
- front_buffer_ ^= 1;
-
- // Unlocking will unset the pixel pointer, so it won't be pointing to the old
- // PixelRef.
- skia_device_->accessBitmap(false).unlockPixels();
- // Update the backing pixels for the bitmap device.
- static_cast<CustomSkBitmapDevice*>(skia_device_.get())->SetPixelRef(
- bitmaps_[front_buffer_ ^ 1]->pixelRef());
- // Locking the pixels will set the pixel pointer based on the PixelRef value.
- skia_device_->accessBitmap(false).lockPixels();
-
- SkIRect device_damage;
- skia_canvas_->getClipDeviceBounds(&device_damage);
- SkRect damage = SkRect::Make(device_damage);
-
- skia_canvas_->drawBitmapRectToRect(*bitmaps_[front_buffer_].get(),
- &damage,
- damage);
-}
-
-SkCanvas* DriSurface::GetDrawableForWidget() {
- return skia_canvas_.get();
-}
-
-DriSkBitmap* DriSurface::CreateBuffer() {
- return new DriSkBitmap(controller_->get_fd());
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/dri/dri_surface.h b/chromium/ui/gfx/ozone/dri/dri_surface.h
deleted file mode 100644
index 53258cf8086..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_surface.h
+++ /dev/null
@@ -1,168 +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_OZONE_DRI_DRI_SURFACE_H_
-#define UI_GFX_OZONE_DRI_DRI_SURFACE_H_
-
-#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/skia_util.h"
-
-class SkBitmapDevice;
-class SkCanvas;
-
-namespace gfx {
-
-class DriSkBitmap;
-class HardwareDisplayController;
-
-// DriSurface is used to represent a surface that can be scanned out
-// to a monitor. It will store the internal state associated with the drawing
-// surface associated with it. DriSurface also performs all the needed
-// operations to initialize and update the drawing surface.
-//
-// The implementation uses dumb buffers, which is used for software rendering.
-// The intent is to have one DriSurface implementation for a
-// HardwareDisplayController.
-//
-// DoubleBufferedSurface is intended to be the software analog to
-// EGLNativeSurface while DriSurface is intended to provide the glue
-// necessary to initialize and display the surface to the screen.
-//
-// The typical usage pattern is:
-// -----------------------------------------------------------------------------
-// HardwareDisplayController controller;
-// // Initialize controller
-//
-// DriSurface* surface = new DriSurface(controller);
-// surface.Initialize();
-// controller.BindSurfaceToController(surface);
-//
-// while (true) {
-// SkCanvas* canvas = surface->GetDrawableForWidget();
-// DrawStuff(canvas);
-// controller.SchedulePageFlip();
-//
-// Wait for page flip event. The DRM page flip handler will call
-// surface.SwapBuffers();
-// }
-//
-// delete surface;
-// -----------------------------------------------------------------------------
-// In the above example the wait consists of reading a DRM pageflip event from
-// the graphics card file descriptor. This is done by calling |drmHandleEvent|,
-// which will read and process the event. |drmHandleEvent| will call a callback
-// registered by |SchedulePageFlip| which will update the internal state.
-//
-// |SchedulePageFlip| can also be used to limit drawing to the screen's vsync
-// since page flips only happen on vsync. In a threaded environment a message
-// loop would listen on the graphics card file descriptor for an event and
-// |drmHandleEvent| would be called from the message loop. The event handler
-// would also be responsible for updating the renderer's state and signal that
-// it is OK to start drawing the next frame.
-//
-// The following example will illustrate the system state transitions in one
-// iteration of the above loop.
-//
-// 1. Both buffers contain the same image with b[0] being the front buffer
-// (star will represent the frontbuffer).
-// ------- -------
-// | | | |
-// | | | |
-// | | | |
-// | | | |
-// ------- -------
-// b[0]* b[1]
-//
-// 2. Call |GetBackbuffer| to get a SkCanvas wrapper for the backbuffer and draw
-// to it.
-// ------- -------
-// | | | |
-// | | | d |
-// | | | |
-// | | | |
-// ------- -------
-// b[0]* b[1]
-//
-// 3. Call |SchedulePageFlip| to display the backbuffer. At this point we can't
-// modify b[0] because it is the frontbuffer and we can't modify b[1] since it
-// has been scheduled for pageflip. If we do draw in b[1] it is possible that
-// the pageflip and draw happen at the same time and we could get tearing.
-//
-// 4. The pageflip callback is called which will call |SwapSurfaces|. Before
-// |SwapSurfaces| is called the state is as following from the hardware's
-// perspective:
-// ------- -------
-// | | | |
-// | | | d |
-// | | | |
-// | | | |
-// ------- -------
-// b[0] b[1]*
-//
-// 5. |SwapSurfaces| will update out internal reference to the front buffer and
-// synchronize the damaged area such that both buffers are identical. The
-// damaged area is used from the SkCanvas clip.
-// ------- -------
-// | | | |
-// | d | | d |
-// | | | |
-// | | | |
-// ------- -------
-// b[0] b[1]*
-//
-// The synchronization consists of copying the damaged area from the frontbuffer
-// to the backbuffer.
-//
-// At this point we're back to step 1 and can start a new draw iteration.
-class GFX_EXPORT DriSurface {
- public:
- DriSurface(HardwareDisplayController* controller);
-
- virtual ~DriSurface();
-
- // Used to allocate all necessary buffers for this surface. If the
- // initialization succeeds, the device is ready to be used for drawing
- // operations.
- // Returns true if the initialization is successful, false otherwise.
- bool Initialize();
-
- // Returns the ID of the current backbuffer.
- uint32_t GetFramebufferId() const;
-
- // Synchronizes and swaps the back buffer with the front buffer.
- void SwapBuffers();
-
- // Get a Skia canvas for a backbuffer.
- SkCanvas* GetDrawableForWidget();
-
- private:
- friend class HardwareDisplayController;
-
- // Used to create the backing buffers.
- virtual DriSkBitmap* CreateBuffer();
-
- // Stores DRM information for this output device (connector, encoder, last
- // CRTC state).
- HardwareDisplayController* controller_;
-
- // The actual buffers used for painting.
- scoped_ptr<DriSkBitmap> bitmaps_[2];
-
- // BitmapDevice for the current backbuffer.
- skia::RefPtr<SkBitmapDevice> skia_device_;
-
- // Canvas for the current backbuffer.
- skia::RefPtr<SkCanvas> skia_canvas_;
-
- // Keeps track of which bitmap is |buffers_| is the frontbuffer.
- int front_buffer_;
-
- DISALLOW_COPY_AND_ASSIGN(DriSurface);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_DRI_DRI_SURFACE_H_
diff --git a/chromium/ui/gfx/ozone/dri/dri_surface_factory.cc b/chromium/ui/gfx/ozone/dri/dri_surface_factory.cc
deleted file mode 100644
index 4c201373942..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_surface_factory.cc
+++ /dev/null
@@ -1,317 +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/ozone/dri/dri_surface_factory.h"
-
-#include <drm.h>
-#include <errno.h>
-#include <xf86drm.h>
-
-#include "base/message_loop/message_loop.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "third_party/skia/include/core/SkDevice.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/ozone/dri/dri_skbitmap.h"
-#include "ui/gfx/ozone/dri/dri_surface.h"
-#include "ui/gfx/ozone/dri/dri_vsync_provider.h"
-#include "ui/gfx/ozone/dri/dri_wrapper.h"
-#include "ui/gfx/ozone/dri/hardware_display_controller.h"
-
-namespace gfx {
-
-namespace {
-
-const char kDefaultGraphicsCardPath[] = "/dev/dri/card0";
-const char kDPMSProperty[] = "DPMS";
-
-const gfx::AcceleratedWidget kDefaultWidgetHandle = 1;
-
-// DRM callback on page flip events. This callback is triggered after the
-// page flip has happened and the backbuffer is now the new frontbuffer
-// The old frontbuffer is no longer used by the hardware and can be used for
-// future draw operations.
-//
-// |device| will contain a reference to the |DriSurface| object which
-// the event belongs to.
-//
-// TODO(dnicoara) When we have a FD handler for the DRM calls in the message
-// loop, we can move this function in the handler.
-void HandlePageFlipEvent(int fd,
- unsigned int frame,
- unsigned int seconds,
- unsigned int useconds,
- void* controller) {
- static_cast<HardwareDisplayController*>(controller)
- ->OnPageFlipEvent(frame, seconds, useconds);
-}
-
-uint32_t GetDriProperty(int fd, drmModeConnector* connector, const char* name) {
- for (int i = 0; i < connector->count_props; ++i) {
- drmModePropertyPtr property = drmModeGetProperty(fd, connector->props[i]);
- if (!property)
- continue;
-
- if (strcmp(property->name, name) == 0) {
- uint32_t id = property->prop_id;
- drmModeFreeProperty(property);
- return id;
- }
-
- drmModeFreeProperty(property);
- }
- return 0;
-}
-
-uint32_t GetCrtc(int fd, drmModeRes* resources, drmModeConnector* connector) {
- // If the connector already has an encoder try to re-use.
- if (connector->encoder_id) {
- drmModeEncoder* encoder = drmModeGetEncoder(fd, connector->encoder_id);
- if (encoder) {
- if (encoder->crtc_id) {
- uint32_t crtc = encoder->crtc_id;
- drmModeFreeEncoder(encoder);
- return crtc;
- }
- drmModeFreeEncoder(encoder);
- }
- }
-
- // Try to find an encoder for the connector.
- for (int i = 0; i < connector->count_encoders; ++i) {
- drmModeEncoder* encoder = drmModeGetEncoder(fd, connector->encoders[i]);
- if (!encoder)
- continue;
-
- for (int j = 0; j < resources->count_crtcs; ++j) {
- // Check if the encoder is compatible with this CRTC
- if (!(encoder->possible_crtcs & (1 << j)))
- continue;
-
- drmModeFreeEncoder(encoder);
- return resources->crtcs[j];
- }
- }
-
- return 0;
-}
-
-} // namespace
-
-DriSurfaceFactory::DriSurfaceFactory()
- : drm_(),
- state_(UNINITIALIZED),
- controller_() {
-}
-
-DriSurfaceFactory::~DriSurfaceFactory() {
- if (state_ == INITIALIZED)
- ShutdownHardware();
-}
-
-SurfaceFactoryOzone::HardwareState
-DriSurfaceFactory::InitializeHardware() {
- CHECK(state_ == UNINITIALIZED);
-
- // TODO(dnicoara): Short-cut right now. What we want is to look at all the
- // graphics devices available and select the primary one.
- drm_.reset(CreateWrapper());
- if (drm_->get_fd() < 0) {
- LOG(ERROR) << "Cannot open graphics card '"
- << kDefaultGraphicsCardPath << "': " << strerror(errno);
- state_ = FAILED;
- return state_;
- }
-
- state_ = INITIALIZED;
- return state_;
-}
-
-void DriSurfaceFactory::ShutdownHardware() {
- CHECK(state_ == INITIALIZED);
-
- controller_.reset();
- drm_.reset();
-
- state_ = UNINITIALIZED;
-}
-
-gfx::AcceleratedWidget DriSurfaceFactory::GetAcceleratedWidget() {
- CHECK(state_ != FAILED);
-
- // TODO(dnicoara) When there's more information on which display we want,
- // then we can return the widget associated with the display.
- // For now just assume we have 1 display device and return it.
- if (!controller_.get())
- controller_.reset(new HardwareDisplayController());
-
- // TODO(dnicoara) We only have 1 display for now, so only 1 AcceleratedWidget.
- // When we'll support multiple displays this needs to be changed to return a
- // different handle for every display.
- return kDefaultWidgetHandle;
-}
-
-gfx::AcceleratedWidget DriSurfaceFactory::RealizeAcceleratedWidget(
- gfx::AcceleratedWidget w) {
- CHECK(state_ == INITIALIZED);
- // TODO(dnicoara) Once we can handle multiple displays this needs to be
- // changed.
- CHECK(w == kDefaultWidgetHandle);
-
- CHECK(controller_->get_state() ==
- HardwareDisplayController::UNASSOCIATED);
-
- // Until now the controller is just a stub. Initializing it will link it to a
- // hardware display.
- if (!InitializeControllerForPrimaryDisplay(drm_.get(), controller_.get())) {
- LOG(ERROR) << "Failed to initialize controller";
- return gfx::kNullAcceleratedWidget;
- }
-
- // Create a surface suitable for the current controller.
- scoped_ptr<DriSurface> surface(CreateSurface(controller_.get()));
-
- if (!surface->Initialize()) {
- LOG(ERROR) << "Failed to initialize surface";
- return gfx::kNullAcceleratedWidget;
- }
-
- // Bind the surface to the controller. This will register the backing buffers
- // with the hardware CRTC such that we can show the buffers. The controller
- // takes ownership of the surface.
- if (!controller_->BindSurfaceToController(surface.Pass())) {
- LOG(ERROR) << "Failed to bind surface to controller";
- return gfx::kNullAcceleratedWidget;
- }
-
- return reinterpret_cast<gfx::AcceleratedWidget>(controller_->get_surface());
-}
-
-bool DriSurfaceFactory::LoadEGLGLES2Bindings(
- AddGLLibraryCallback add_gl_library,
- SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
- return false;
-}
-
-bool DriSurfaceFactory::AttemptToResizeAcceleratedWidget(
- gfx::AcceleratedWidget w,
- const gfx::Rect& bounds) {
- return false;
-}
-
-bool DriSurfaceFactory::SchedulePageFlip(gfx::AcceleratedWidget w) {
- CHECK(state_ == INITIALIZED);
- // TODO(dnicoara) Change this CHECK once we're running with the threaded
- // compositor.
- CHECK(base::MessageLoop::current()->type() == base::MessageLoop::TYPE_UI);
-
- // TODO(dnicoara) Once we can handle multiple displays this needs to be
- // changed.
- CHECK(w == kDefaultWidgetHandle);
-
- if (!controller_->SchedulePageFlip())
- return false;
-
- // Only wait for the page flip event to finish if it was properly scheduled.
- //
- // TODO(dnicoara) The following call will wait for the page flip event to
- // complete. This means that it will block until the next VSync. Ideally the
- // wait should happen in the message loop. The message loop would then
- // schedule the next draw event. Alternatively, the VSyncProvider could be
- // used to schedule the next draw. Unfortunately, at this point,
- // DriOutputDevice does not provide any means to use any of the above
- // solutions. Note that if the DRM callback does not schedule the next draw,
- // then some sort of synchronization needs to take place since starting a new
- // draw before the page flip happened is considered an error. However we can
- // not use any lock constructs unless we're using the threaded compositor.
- // Note that the following call does not use any locks, so it is safe to be
- // made on the UI thread (thought not ideal).
- WaitForPageFlipEvent(drm_->get_fd());
-
- return true;
-}
-
-SkCanvas* DriSurfaceFactory::GetCanvasForWidget(
- gfx::AcceleratedWidget w) {
- CHECK(state_ == INITIALIZED);
- return reinterpret_cast<DriSurface*>(w)->GetDrawableForWidget();
-}
-
-gfx::VSyncProvider* DriSurfaceFactory::GetVSyncProvider(
- gfx::AcceleratedWidget w) {
- CHECK(state_ == INITIALIZED);
- return new DriVSyncProvider(controller_.get());
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DriSurfaceFactory private
-
-DriSurface* DriSurfaceFactory::CreateSurface(
- HardwareDisplayController* controller) {
- return new DriSurface(controller);
-}
-
-DriWrapper* DriSurfaceFactory::CreateWrapper() {
- return new DriWrapper(kDefaultGraphicsCardPath);
-}
-
-bool DriSurfaceFactory::InitializeControllerForPrimaryDisplay(
- DriWrapper* drm,
- HardwareDisplayController* controller) {
- CHECK(state_ == SurfaceFactoryOzone::INITIALIZED);
-
- drmModeRes* resources = drmModeGetResources(drm->get_fd());
-
- // Search for an active connector.
- for (int i = 0; i < resources->count_connectors; ++i) {
- drmModeConnector* connector = drmModeGetConnector(
- drm->get_fd(),
- resources->connectors[i]);
-
- if (!connector)
- continue;
-
- if (connector->connection != DRM_MODE_CONNECTED ||
- connector->count_modes == 0) {
- drmModeFreeConnector(connector);
- continue;
- }
-
- uint32_t crtc = GetCrtc(drm->get_fd(), resources, connector);
-
- if (!crtc)
- continue;
-
- uint32_t dpms_property_id = GetDriProperty(drm->get_fd(),
- connector,
- kDPMSProperty);
-
- // TODO(dnicoara) Select one mode for now. In the future we may need to
- // save all the modes and allow the user to choose a specific mode. Or
- // even some fullscreen applications may need to change the mode.
- controller->SetControllerInfo(
- drm,
- connector->connector_id,
- crtc,
- dpms_property_id,
- connector->modes[0]);
-
- drmModeFreeConnector(connector);
-
- return true;
- }
-
- return false;
-}
-
-void DriSurfaceFactory::WaitForPageFlipEvent(int fd) {
- drmEventContext drm_event;
- drm_event.version = DRM_EVENT_CONTEXT_VERSION;
- drm_event.page_flip_handler = HandlePageFlipEvent;
- drm_event.vblank_handler = NULL;
-
- // Wait for the page-flip to complete.
- drmHandleEvent(fd, &drm_event);
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/dri/dri_surface_factory.h b/chromium/ui/gfx/ozone/dri/dri_surface_factory.h
deleted file mode 100644
index 616e989e910..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_surface_factory.h
+++ /dev/null
@@ -1,75 +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_OZONE_DRI_DRI_SURFACE_FACTORY_H_
-#define UI_GFX_OZONE_DRI_DRI_SURFACE_FACTORY_H_
-
-#include "base/memory/scoped_ptr.h"
-#include "ui/gfx/ozone/surface_factory_ozone.h"
-
-namespace gfx {
-
-class DriSurface;
-class DriWrapper;
-class HardwareDisplayController;
-
-// SurfaceFactoryOzone implementation on top of DRM/KMS using dumb buffers.
-// This implementation is used in conjunction with the software rendering
-// path.
-class GFX_EXPORT DriSurfaceFactory : public SurfaceFactoryOzone {
- public:
- DriSurfaceFactory();
- virtual ~DriSurfaceFactory();
-
- virtual HardwareState InitializeHardware() OVERRIDE;
- virtual void ShutdownHardware() OVERRIDE;
-
- virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
- virtual gfx::AcceleratedWidget RealizeAcceleratedWidget(
- gfx::AcceleratedWidget w) OVERRIDE;
-
- virtual bool LoadEGLGLES2Bindings(
- AddGLLibraryCallback add_gl_library,
- SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
-
- virtual bool AttemptToResizeAcceleratedWidget(
- gfx::AcceleratedWidget w,
- const gfx::Rect& bounds) OVERRIDE;
-
- virtual bool SchedulePageFlip(gfx::AcceleratedWidget w) OVERRIDE;
-
- virtual SkCanvas* GetCanvasForWidget(gfx::AcceleratedWidget w) OVERRIDE;
-
- virtual gfx::VSyncProvider* GetVSyncProvider(
- gfx::AcceleratedWidget w) OVERRIDE;
-
- private:
- virtual DriSurface* CreateSurface(
- HardwareDisplayController* controller);
-
- virtual DriWrapper* CreateWrapper();
-
- virtual bool InitializeControllerForPrimaryDisplay(
- DriWrapper* drm,
- HardwareDisplayController* controller);
-
- // Blocks until a DRM event is read.
- // TODO(dnicoara) Remove once we can safely move DRM event processing in the
- // message loop while correctly signaling when we're done displaying the
- // pending frame.
- virtual void WaitForPageFlipEvent(int fd);
-
- scoped_ptr<DriWrapper> drm_;
-
- HardwareState state_;
-
- // Active output.
- scoped_ptr<HardwareDisplayController> controller_;
-
- DISALLOW_COPY_AND_ASSIGN(DriSurfaceFactory);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_DRI_DRI_SURFACE_FACTORY_H_
diff --git a/chromium/ui/gfx/ozone/dri/dri_surface_factory_unittest.cc b/chromium/ui/gfx/ozone/dri/dri_surface_factory_unittest.cc
deleted file mode 100644
index 2e70f642f2a..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_surface_factory_unittest.cc
+++ /dev/null
@@ -1,292 +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 "base/memory/scoped_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/ozone/dri/dri_skbitmap.h"
-#include "ui/gfx/ozone/dri/dri_surface.h"
-#include "ui/gfx/ozone/dri/dri_surface_factory.h"
-#include "ui/gfx/ozone/dri/dri_wrapper.h"
-#include "ui/gfx/ozone/dri/hardware_display_controller.h"
-#include "ui/gfx/ozone/surface_factory_ozone.h"
-
-namespace {
-
-const drmModeModeInfo kDefaultMode =
- {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
-
-// Mock file descriptor ID.
-const int kFd = 3;
-
-// Mock connector ID.
-const uint32_t kConnectorId = 1;
-
-// Mock CRTC ID.
-const uint32_t kCrtcId = 1;
-
-const uint32_t kDPMSPropertyId = 1;
-
-const gfx::AcceleratedWidget kDefaultWidgetHandle = 1;
-
-// The real DriWrapper makes actual DRM calls which we can't use in unit tests.
-class MockDriWrapper : public gfx::DriWrapper {
- public:
- MockDriWrapper(int fd) : DriWrapper(""),
- add_framebuffer_expectation_(true),
- page_flip_expectation_(true) {
- fd_ = fd;
- }
-
- virtual ~MockDriWrapper() { fd_ = -1; }
-
- virtual drmModeCrtc* GetCrtc(uint32_t crtc_id) OVERRIDE {
- return new drmModeCrtc;
- }
-
- virtual void FreeCrtc(drmModeCrtc* crtc) OVERRIDE {
- delete crtc;
- }
-
- virtual bool SetCrtc(uint32_t crtc_id,
- uint32_t framebuffer,
- uint32_t* connectors,
- drmModeModeInfo* mode) OVERRIDE {
- return true;
- }
-
- virtual bool SetCrtc(drmModeCrtc* crtc, uint32_t* connectors) OVERRIDE {
- return true;
- }
-
- virtual bool AddFramebuffer(const drmModeModeInfo& mode,
- uint8_t depth,
- uint8_t bpp,
- uint32_t stride,
- uint32_t handle,
- uint32_t* framebuffer) OVERRIDE {
- return add_framebuffer_expectation_;
- }
-
- virtual bool RemoveFramebuffer(uint32_t framebuffer) OVERRIDE { return true; }
-
- virtual bool PageFlip(uint32_t crtc_id,
- uint32_t framebuffer,
- void* data) OVERRIDE {
- static_cast<gfx::HardwareDisplayController*>(data)->get_surface()
- ->SwapBuffers();
- return page_flip_expectation_;
- }
-
- virtual bool ConnectorSetProperty(uint32_t connector_id,
- uint32_t property_id,
- uint64_t value) OVERRIDE { return true; }
-
- void set_add_framebuffer_expectation(bool state) {
- add_framebuffer_expectation_ = state;
- }
-
- void set_page_flip_expectation(bool state) {
- page_flip_expectation_ = state;
- }
-
- private:
- bool add_framebuffer_expectation_;
- bool page_flip_expectation_;
-
- DISALLOW_COPY_AND_ASSIGN(MockDriWrapper);
-};
-
-class MockDriSkBitmap : public gfx::DriSkBitmap {
- public:
- MockDriSkBitmap() : DriSkBitmap(kFd) {}
- virtual ~MockDriSkBitmap() {}
-
- virtual bool Initialize() OVERRIDE {
- allocPixels();
- eraseColor(SK_ColorBLACK);
- return true;
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(MockDriSkBitmap);
-};
-
-class MockDriSurface : public gfx::DriSurface {
- public:
- MockDriSurface(gfx::HardwareDisplayController* controller)
- : DriSurface(controller) {}
- virtual ~MockDriSurface() {}
-
- private:
- virtual gfx::DriSkBitmap* CreateBuffer() OVERRIDE {
- return new MockDriSkBitmap();
- }
-
- DISALLOW_COPY_AND_ASSIGN(MockDriSurface);
-};
-
-// SSFO would normally allocate DRM resources. We can't rely on having a DRM
-// backend to allocate and display our buffers. Thus, we replace these
-// resources with stubs. For DRM calls, we simply use stubs that do nothing and
-// for buffers we use the default SkBitmap allocator.
-class MockDriSurfaceFactory
- : public gfx::DriSurfaceFactory {
- public:
- MockDriSurfaceFactory()
- : DriSurfaceFactory(),
- mock_drm_(NULL),
- drm_wrapper_expectation_(true),
- initialize_controller_expectation_(true) {}
- virtual ~MockDriSurfaceFactory() {};
-
- void set_drm_wrapper_expectation(bool state) {
- drm_wrapper_expectation_ = state;
- }
-
- void set_initialize_controller_expectation(bool state) {
- initialize_controller_expectation_ = state;
- }
-
- MockDriWrapper* get_drm() const {
- return mock_drm_;
- }
-
- private:
- virtual gfx::DriSurface* CreateSurface(
- gfx::HardwareDisplayController* controller) OVERRIDE {
- return new MockDriSurface(controller);
- }
-
- virtual gfx::DriWrapper* CreateWrapper() OVERRIDE {
- if (drm_wrapper_expectation_)
- mock_drm_ = new MockDriWrapper(kFd);
- else
- mock_drm_ = new MockDriWrapper(-1);
-
- return mock_drm_;
- }
-
- // Normally we'd use DRM to figure out the controller configuration. But we
- // can't use DRM in unit tests, so we just create a fake configuration.
- virtual bool InitializeControllerForPrimaryDisplay(
- gfx::DriWrapper* drm,
- gfx::HardwareDisplayController* controller) OVERRIDE {
- if (initialize_controller_expectation_) {
- controller->SetControllerInfo(drm,
- kConnectorId,
- kCrtcId,
- kDPMSPropertyId,
- kDefaultMode);
- return true;
- } else {
- return false;
- }
- }
-
- virtual void WaitForPageFlipEvent(int fd) OVERRIDE {}
-
- MockDriWrapper* mock_drm_;
- bool drm_wrapper_expectation_;
- bool initialize_controller_expectation_;
-
- DISALLOW_COPY_AND_ASSIGN(MockDriSurfaceFactory);
-};
-
-} // namespace
-
-class DriSurfaceFactoryTest : public testing::Test {
- public:
- DriSurfaceFactoryTest() {}
-
- virtual void SetUp() OVERRIDE;
- virtual void TearDown() OVERRIDE;
- protected:
- scoped_ptr<base::MessageLoop> message_loop_;
- scoped_ptr<MockDriSurfaceFactory> factory_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DriSurfaceFactoryTest);
-};
-
-void DriSurfaceFactoryTest::SetUp() {
- message_loop_.reset(new base::MessageLoop(base::MessageLoop::TYPE_UI));
- factory_.reset(new MockDriSurfaceFactory());
-}
-
-void DriSurfaceFactoryTest::TearDown() {
- factory_.reset();
- message_loop_.reset();
-}
-
-TEST_F(DriSurfaceFactoryTest, FailInitialization) {
- factory_->set_drm_wrapper_expectation(false);
-
- EXPECT_EQ(gfx::SurfaceFactoryOzone::FAILED, factory_->InitializeHardware());
-}
-
-TEST_F(DriSurfaceFactoryTest, SuccessfulInitialization) {
- EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
- factory_->InitializeHardware());
-}
-
-TEST_F(DriSurfaceFactoryTest, FailSurfaceInitialization) {
- factory_->set_initialize_controller_expectation(false);
-
- EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
- factory_->InitializeHardware());
-
- gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
- EXPECT_EQ(kDefaultWidgetHandle, w);
-
- EXPECT_EQ(gfx::kNullAcceleratedWidget, factory_->RealizeAcceleratedWidget(w));
-}
-
-TEST_F(DriSurfaceFactoryTest, FailBindingSurfaceToController) {
- EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
- factory_->InitializeHardware());
-
- factory_->get_drm()->set_add_framebuffer_expectation(false);
-
- gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
- EXPECT_EQ(kDefaultWidgetHandle, w);
-
- EXPECT_EQ(gfx::kNullAcceleratedWidget, factory_->RealizeAcceleratedWidget(w));
-}
-
-TEST_F(DriSurfaceFactoryTest, SuccessfulWidgetRealization) {
- EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
- factory_->InitializeHardware());
-
- gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
- EXPECT_EQ(kDefaultWidgetHandle, w);
-
- EXPECT_NE(gfx::kNullAcceleratedWidget, factory_->RealizeAcceleratedWidget(w));
-}
-
-TEST_F(DriSurfaceFactoryTest, FailSchedulePageFlip) {
- EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
- factory_->InitializeHardware());
-
- factory_->get_drm()->set_page_flip_expectation(false);
-
- gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
- EXPECT_EQ(kDefaultWidgetHandle, w);
-
- EXPECT_NE(gfx::kNullAcceleratedWidget, factory_->RealizeAcceleratedWidget(w));
-
- EXPECT_FALSE(factory_->SchedulePageFlip(w));
-}
-
-TEST_F(DriSurfaceFactoryTest, SuccessfulSchedulePageFlip) {
- EXPECT_EQ(gfx::SurfaceFactoryOzone::INITIALIZED,
- factory_->InitializeHardware());
-
- gfx::AcceleratedWidget w = factory_->GetAcceleratedWidget();
- EXPECT_EQ(kDefaultWidgetHandle, w);
-
- EXPECT_NE(gfx::kNullAcceleratedWidget, factory_->RealizeAcceleratedWidget(w));
-
- EXPECT_TRUE(factory_->SchedulePageFlip(w));
-}
diff --git a/chromium/ui/gfx/ozone/dri/dri_surface_unittest.cc b/chromium/ui/gfx/ozone/dri/dri_surface_unittest.cc
deleted file mode 100644
index 754659163a2..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_surface_unittest.cc
+++ /dev/null
@@ -1,212 +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 "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "third_party/skia/include/core/SkDevice.h"
-#include "ui/gfx/ozone/dri/dri_skbitmap.h"
-#include "ui/gfx/ozone/dri/dri_surface.h"
-#include "ui/gfx/ozone/dri/hardware_display_controller.h"
-
-namespace {
-
-// Create a basic mode for a 6x4 screen.
-const drmModeModeInfo kDefaultMode =
- {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
-
-// Mock file descriptor ID.
-const int kFd = 3;
-
-// Mock connector ID.
-const uint32_t kConnectorId = 1;
-
-// Mock CRTC ID.
-const uint32_t kCrtcId = 1;
-
-// Mock DPMS property ID.
-const uint32_t kDPMSPropertyId = 1;
-
-class MockDriWrapper : public gfx::DriWrapper {
- public:
- MockDriWrapper() : DriWrapper(""), id_(1) { fd_ = kFd; }
- virtual ~MockDriWrapper() { fd_ = -1; }
-
- virtual drmModeCrtc* GetCrtc(uint32_t crtc_id) OVERRIDE { return NULL; }
- virtual void FreeCrtc(drmModeCrtc* crtc) OVERRIDE {}
- virtual bool SetCrtc(uint32_t crtc_id,
- uint32_t framebuffer,
- uint32_t* connectors,
- drmModeModeInfo* mode) OVERRIDE { return true; }
- virtual bool SetCrtc(drmModeCrtc* crtc, uint32_t* connectors) OVERRIDE {
- return true;
- }
- virtual bool AddFramebuffer(const drmModeModeInfo& mode,
- uint8_t depth,
- uint8_t bpp,
- uint32_t stride,
- uint32_t handle,
- uint32_t* framebuffer) OVERRIDE {
- *framebuffer = id_++;
- return true;
- }
- virtual bool RemoveFramebuffer(uint32_t framebuffer) OVERRIDE { return true; }
- virtual bool PageFlip(uint32_t crtc_id,
- uint32_t framebuffer,
- void* data) OVERRIDE {
- return true;
- }
- virtual bool ConnectorSetProperty(uint32_t connector_id,
- uint32_t property_id,
- uint64_t value) OVERRIDE { return true; }
-
- private:
- int id_;
- DISALLOW_COPY_AND_ASSIGN(MockDriWrapper);
-};
-
-class MockDriSkBitmap : public gfx::DriSkBitmap {
- public:
- MockDriSkBitmap(int fd,
- bool initialize_expectation)
- : DriSkBitmap(fd),
- initialize_expectation_(initialize_expectation) {}
- virtual ~MockDriSkBitmap() {}
-
- virtual bool Initialize() OVERRIDE {
- if (!initialize_expectation_)
- return false;
-
- allocPixels();
- // Clear the bitmap to black.
- eraseColor(SK_ColorBLACK);
-
- return true;
- }
- private:
- bool initialize_expectation_;
-
- DISALLOW_COPY_AND_ASSIGN(MockDriSkBitmap);
-};
-
-class MockDriSurface : public gfx::DriSurface {
- public:
- MockDriSurface(gfx::HardwareDisplayController* controller)
- : DriSurface(controller),
- initialize_expectation_(true) {}
- virtual ~MockDriSurface() {}
-
- void set_initialize_expectation(bool state) {
- initialize_expectation_ = state;
- }
-
- private:
- virtual gfx::DriSkBitmap* CreateBuffer() OVERRIDE {
- return new MockDriSkBitmap(kFd, initialize_expectation_);
- }
-
- bool initialize_expectation_;
-
- DISALLOW_COPY_AND_ASSIGN(MockDriSurface);
-};
-
-} // namespace
-
-class DriSurfaceTest : public testing::Test {
- public:
- DriSurfaceTest() {}
-
- virtual void SetUp() OVERRIDE;
- virtual void TearDown() OVERRIDE;
-
- protected:
- scoped_ptr<MockDriWrapper> drm_;
- scoped_ptr<gfx::HardwareDisplayController> controller_;
- scoped_ptr<MockDriSurface> surface_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DriSurfaceTest);
-};
-
-void DriSurfaceTest::SetUp() {
- drm_.reset(new MockDriWrapper());
- controller_.reset(new gfx::HardwareDisplayController());
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
-
- surface_.reset(new MockDriSurface(controller_.get()));
-}
-
-void DriSurfaceTest::TearDown() {
- surface_.reset();
- controller_.reset();
- drm_.reset();
-}
-
-TEST_F(DriSurfaceTest, FailInitialization) {
- surface_->set_initialize_expectation(false);
- EXPECT_FALSE(surface_->Initialize());
-}
-
-TEST_F(DriSurfaceTest, SuccessfulInitialization) {
- EXPECT_TRUE(surface_->Initialize());
-}
-
-TEST_F(DriSurfaceTest, CheckFBIDOnSwap) {
- EXPECT_TRUE(surface_->Initialize());
- controller_->BindSurfaceToController(
- surface_.PassAs<gfx::DriSurface>());
-
- // Check that the framebuffer ID is correct.
- EXPECT_EQ(2u, controller_->get_surface()->GetFramebufferId());
-
- controller_->get_surface()->SwapBuffers();
-
- EXPECT_EQ(1u, controller_->get_surface()->GetFramebufferId());
-}
-
-TEST_F(DriSurfaceTest, CheckPixelPointerOnSwap) {
- EXPECT_TRUE(surface_->Initialize());
-
- void* bitmap_pixels1 = surface_->GetDrawableForWidget()->getDevice()
- ->accessBitmap(false).getPixels();
-
- surface_->SwapBuffers();
-
- void* bitmap_pixels2 = surface_->GetDrawableForWidget()->getDevice()
- ->accessBitmap(false).getPixels();
-
- // Check that once the buffers have been swapped the drawable's underlying
- // pixels have been changed.
- EXPECT_NE(bitmap_pixels1, bitmap_pixels2);
-}
-
-TEST_F(DriSurfaceTest, CheckCorrectBufferSync) {
- EXPECT_TRUE(surface_->Initialize());
-
- SkCanvas* canvas = surface_->GetDrawableForWidget();
- SkRect clip;
- // Modify part of the canvas.
- clip.set(0, 0,
- canvas->getDeviceSize().width() / 2,
- canvas->getDeviceSize().height() / 2);
- canvas->clipRect(clip, SkRegion::kReplace_Op);
-
- canvas->drawColor(SK_ColorWHITE);
-
- surface_->SwapBuffers();
-
- // Verify that the modified contents have been copied over on swap (make sure
- // the 2 buffers have the same content).
- for (int i = 0; i < canvas->getDeviceSize().height(); ++i) {
- for (int j = 0; j < canvas->getDeviceSize().width(); ++j) {
- if (i < clip.height() && j < clip.width())
- EXPECT_EQ(SK_ColorWHITE,
- canvas->getDevice()->accessBitmap(false).getColor(j, i));
- else
- EXPECT_EQ(SK_ColorBLACK,
- canvas->getDevice()->accessBitmap(false).getColor(j, i));
- }
- }
-}
diff --git a/chromium/ui/gfx/ozone/dri/dri_vsync_provider.cc b/chromium/ui/gfx/ozone/dri/dri_vsync_provider.cc
deleted file mode 100644
index b5717e686f1..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_vsync_provider.cc
+++ /dev/null
@@ -1,32 +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/ozone/dri/dri_vsync_provider.h"
-
-#include "base/time/time.h"
-#include "ui/gfx/ozone/dri/hardware_display_controller.h"
-
-namespace gfx {
-
-DriVSyncProvider::DriVSyncProvider(HardwareDisplayController* controller)
- : controller_(controller) {}
-
-DriVSyncProvider::~DriVSyncProvider() {}
-
-void DriVSyncProvider::GetVSyncParameters(const UpdateVSyncCallback& callback) {
- // The value is invalid, so we can't update the parameters.
- if (controller_->get_time_of_last_flip() == 0)
- return;
-
- // Stores the time of the last refresh.
- base::TimeTicks timebase =
- base::TimeTicks::FromInternalValue(controller_->get_time_of_last_flip());
- // Stores the refresh rate.
- base::TimeDelta interval =
- base::TimeDelta::FromSeconds(1) / controller_->get_mode().vrefresh;
-
- callback.Run(timebase, interval);
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/dri/dri_vsync_provider.h b/chromium/ui/gfx/ozone/dri/dri_vsync_provider.h
deleted file mode 100644
index b6cb6047eb8..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_vsync_provider.h
+++ /dev/null
@@ -1,29 +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_OZONE_IMPL_DRI_VSYNC_PROVIDER_H_
-#define UI_GFX_OZONE_IMPL_DRI_VSYNC_PROVIDER_H_
-
-#include "ui/gfx/vsync_provider.h"
-
-namespace gfx {
-
-class HardwareDisplayController;
-
-class DriVSyncProvider : public VSyncProvider {
- public:
- DriVSyncProvider(HardwareDisplayController* controller);
- virtual ~DriVSyncProvider();
-
- virtual void GetVSyncParameters(const UpdateVSyncCallback& callback) OVERRIDE;
-
- private:
- HardwareDisplayController* controller_;
-
- DISALLOW_COPY_AND_ASSIGN(DriVSyncProvider);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_IMPL_DRI_VSYNC_PROVIDER_H_
diff --git a/chromium/ui/gfx/ozone/dri/dri_wrapper.cc b/chromium/ui/gfx/ozone/dri/dri_wrapper.cc
deleted file mode 100644
index 2b1104b444d..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_wrapper.cc
+++ /dev/null
@@ -1,93 +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/ozone/dri/dri_wrapper.h"
-
-#include <fcntl.h>
-#include <unistd.h>
-#include <xf86drmMode.h>
-
-#include "base/logging.h"
-
-namespace gfx {
-
-DriWrapper::DriWrapper(const char* device_path) {
- fd_ = open(device_path, O_RDWR | O_CLOEXEC);
-}
-
-DriWrapper::~DriWrapper() {
- if (fd_ >= 0)
- close(fd_);
-}
-
-drmModeCrtc* DriWrapper::GetCrtc(uint32_t crtc_id) {
- CHECK(fd_ >= 0);
- return drmModeGetCrtc(fd_, crtc_id);
-}
-
-void DriWrapper::FreeCrtc(drmModeCrtc* crtc) {
- drmModeFreeCrtc(crtc);
-}
-
-bool DriWrapper::SetCrtc(uint32_t crtc_id,
- uint32_t framebuffer,
- uint32_t* connectors,
- drmModeModeInfo* mode) {
- CHECK(fd_ >= 0);
- return !drmModeSetCrtc(fd_, crtc_id, framebuffer, 0, 0, connectors, 1, mode);
-}
-
-bool DriWrapper::SetCrtc(drmModeCrtc* crtc, uint32_t* connectors) {
- CHECK(fd_ >= 0);
- return !drmModeSetCrtc(fd_,
- crtc->crtc_id,
- crtc->buffer_id,
- crtc->x,
- crtc->y,
- connectors,
- 1,
- &crtc->mode);
-}
-
-bool DriWrapper::AddFramebuffer(const drmModeModeInfo& mode,
- uint8_t depth,
- uint8_t bpp,
- uint32_t stride,
- uint32_t handle,
- uint32_t* framebuffer) {
- CHECK(fd_ >= 0);
- return !drmModeAddFB(fd_,
- mode.hdisplay,
- mode.vdisplay,
- depth,
- bpp,
- stride,
- handle,
- framebuffer);
-}
-
-bool DriWrapper::RemoveFramebuffer(uint32_t framebuffer) {
- CHECK(fd_ >= 0);
- return !drmModeRmFB(fd_, framebuffer);
-}
-
-bool DriWrapper::PageFlip(uint32_t crtc_id,
- uint32_t framebuffer,
- void* data) {
- CHECK(fd_ >= 0);
- return !drmModePageFlip(fd_,
- crtc_id,
- framebuffer,
- DRM_MODE_PAGE_FLIP_EVENT,
- data);
-}
-
-bool DriWrapper::ConnectorSetProperty(uint32_t connector_id,
- uint32_t property_id,
- uint64_t value) {
- CHECK(fd_ >= 0);
- return !drmModeConnectorSetProperty(fd_, connector_id, property_id, value);
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/dri/dri_wrapper.h b/chromium/ui/gfx/ozone/dri/dri_wrapper.h
deleted file mode 100644
index 0848132c9ad..00000000000
--- a/chromium/ui/gfx/ozone/dri/dri_wrapper.h
+++ /dev/null
@@ -1,86 +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_OZONE_DRI_DRI_WRAPPER_H_
-#define UI_GFX_OZONE_DRI_DRI_WRAPPER_H_
-
-#include <stdint.h>
-
-#include "base/basictypes.h"
-#include "ui/gfx/gfx_export.h"
-
-typedef struct _drmModeCrtc drmModeCrtc;
-typedef struct _drmModeModeInfo drmModeModeInfo;
-
-namespace gfx {
-
-// Wraps DRM calls into a nice interface. Used to provide different
-// implementations of the DRM calls. For the actual implementation the DRM API
-// would be called. In unit tests this interface would be stubbed.
-class GFX_EXPORT DriWrapper {
- public:
- DriWrapper(const char* device_path);
- virtual ~DriWrapper();
-
- // Get the CRTC state. This is generally used to save state before using the
- // CRTC. When the user finishes using the CRTC, the user should restore the
- // CRTC to it's initial state. Use |SetCrtc| to restore the state.
- virtual drmModeCrtc* GetCrtc(uint32_t crtc_id);
-
- // Frees the CRTC mode object.
- virtual void FreeCrtc(drmModeCrtc* crtc);
-
- // Used to configure CRTC with ID |crtc_id| to use the connector in
- // |connectors|. The CRTC will be configured with mode |mode| and will display
- // the framebuffer with ID |framebuffer|. Before being able to display the
- // framebuffer, it should be registered with the CRTC using |AddFramebuffer|.
- virtual bool SetCrtc(uint32_t crtc_id,
- uint32_t framebuffer,
- uint32_t* connectors,
- drmModeModeInfo* mode);
-
- // Used to set a specific configuration to the CRTC. Normally this function
- // would be called with a CRTC saved state (from |GetCrtc|) to restore it to
- // its original configuration.
- virtual bool SetCrtc(drmModeCrtc* crtc, uint32_t* connectors);
-
- // Register a buffer with the CRTC. On successful registration, the CRTC will
- // assign a framebuffer ID to |framebuffer|.
- virtual bool AddFramebuffer(const drmModeModeInfo& mode,
- uint8_t depth,
- uint8_t bpp,
- uint32_t stride,
- uint32_t handle,
- uint32_t* framebuffer);
-
- // Deregister the given |framebuffer|.
- virtual bool RemoveFramebuffer(uint32_t framebuffer);
-
- // Schedules a pageflip for CRTC |crtc_id|. This function will return
- // immediately. Upon completion of the pageflip event, the CRTC will be
- // displaying the buffer with ID |framebuffer| and will have a DRM event
- // queued on |fd_|. |data| is a generic pointer to some information the user
- // will receive when processing the pageflip event.
- virtual bool PageFlip(uint32_t crtc_id, uint32_t framebuffer, void* data);
-
- // Sets the value of property with ID |property_id| to |value|. The property
- // is applied to the connector with ID |connector_id|.
- virtual bool ConnectorSetProperty(uint32_t connector_id,
- uint32_t property_id,
- uint64_t value);
-
- int get_fd() const { return fd_; }
-
- protected:
- // The file descriptor associated with this wrapper. All DRM operations will
- // be performed using this FD.
- int fd_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DriWrapper);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_DRI_DRI_WRAPPER_H_
diff --git a/chromium/ui/gfx/ozone/dri/hardware_display_controller.cc b/chromium/ui/gfx/ozone/dri/hardware_display_controller.cc
deleted file mode 100644
index 6accfc00d53..00000000000
--- a/chromium/ui/gfx/ozone/dri/hardware_display_controller.cc
+++ /dev/null
@@ -1,129 +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/ozone/dri/hardware_display_controller.h"
-
-#include <errno.h>
-#include <string.h>
-
-#include "base/basictypes.h"
-#include "base/logging.h"
-#include "base/time/time.h"
-#include "ui/gfx/ozone/dri/dri_skbitmap.h"
-#include "ui/gfx/ozone/dri/dri_surface.h"
-#include "ui/gfx/ozone/dri/dri_wrapper.h"
-
-namespace gfx {
-
-HardwareDisplayController::HardwareDisplayController()
- : drm_(NULL),
- connector_id_(0),
- crtc_id_(0),
- mode_(),
- saved_crtc_(NULL),
- state_(UNASSOCIATED),
- surface_(),
- time_of_last_flip_(0) {}
-
-void HardwareDisplayController::SetControllerInfo(
- DriWrapper* drm,
- uint32_t connector_id,
- uint32_t crtc_id,
- uint32_t dpms_property_id,
- drmModeModeInfo mode) {
- drm_ = drm;
- connector_id_ = connector_id;
- crtc_id_ = crtc_id;
- dpms_property_id_ = dpms_property_id;
- mode_ = mode;
- saved_crtc_ = drm_->GetCrtc(crtc_id_);
- state_ = UNINITIALIZED;
-}
-
-HardwareDisplayController::~HardwareDisplayController() {
- if (saved_crtc_) {
- if (!drm_->SetCrtc(saved_crtc_, &connector_id_))
- DLOG(ERROR) << "Failed to restore CRTC state: " << strerror(errno);
- drm_->FreeCrtc(saved_crtc_);
- }
-
- if (surface_.get()) {
- // Unregister the buffers.
- for (int i = 0; i < 2; ++i) {
- if (!drm_->RemoveFramebuffer(surface_->bitmaps_[i]->get_framebuffer()))
- DLOG(ERROR) << "Failed to remove FB: " << strerror(errno);
- }
- }
-}
-
-bool
-HardwareDisplayController::BindSurfaceToController(
- scoped_ptr<DriSurface> surface) {
- CHECK(state_ == UNINITIALIZED);
-
- // Register the buffers.
- for (int i = 0; i < 2; ++i) {
- uint32_t fb_id;
- if (!drm_->AddFramebuffer(mode_,
- surface->bitmaps_[i]->GetColorDepth(),
- surface->bitmaps_[i]->bytesPerPixel() << 3,
- surface->bitmaps_[i]->rowBytes(),
- surface->bitmaps_[i]->get_handle(),
- &fb_id)) {
- DLOG(ERROR) << "Failed to register framebuffer: " << strerror(errno);
- state_ = FAILED;
- return false;
- }
- surface->bitmaps_[i]->set_framebuffer(fb_id);
- }
-
- surface_.reset(surface.release());
- state_ = SURFACE_INITIALIZED;
- return true;
-}
-
-bool HardwareDisplayController::SchedulePageFlip() {
- CHECK(state_ == SURFACE_INITIALIZED || state_ == INITIALIZED);
-
- if (state_ == SURFACE_INITIALIZED) {
- // Perform the initial modeset.
- if (!drm_->SetCrtc(crtc_id_,
- surface_->GetFramebufferId(),
- &connector_id_,
- &mode_)) {
- DLOG(ERROR) << "Cannot set CRTC: " << strerror(errno);
- state_ = FAILED;
- return false;
- } else {
- state_ = INITIALIZED;
- }
-
- if (dpms_property_id_)
- drm_->ConnectorSetProperty(connector_id_,
- dpms_property_id_,
- DRM_MODE_DPMS_ON);
- }
-
- if (!drm_->PageFlip(crtc_id_,
- surface_->GetFramebufferId(),
- this)) {
- state_ = FAILED;
- LOG(ERROR) << "Cannot page flip: " << strerror(errno);
- return false;
- }
-
- return true;
-}
-
-void HardwareDisplayController::OnPageFlipEvent(unsigned int frame,
- unsigned int seconds,
- unsigned int useconds) {
- time_of_last_flip_ =
- static_cast<uint64_t>(seconds) * base::Time::kMicrosecondsPerSecond +
- useconds;
-
- surface_->SwapBuffers();
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/dri/hardware_display_controller.h b/chromium/ui/gfx/ozone/dri/hardware_display_controller.h
deleted file mode 100644
index cae8a6ba821..00000000000
--- a/chromium/ui/gfx/ozone/dri/hardware_display_controller.h
+++ /dev/null
@@ -1,190 +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_OZONE_DRI_HARDWARE_DISPLAY_CONTROLLER_H_
-#define UI_GFX_OZONE_DRI_HARDWARE_DISPLAY_CONTROLLER_H_
-
-#include <stddef.h>
-#include <stdint.h>
-#include <xf86drmMode.h>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/ozone/dri/dri_wrapper.h"
-
-namespace gfx {
-
-class DriSurface;
-
-// The HDCOz will handle modesettings and scannout operations for hardware
-// devices.
-//
-// In the DRM world there are 3 components that need to be paired up to be able
-// to display an image to the monitor: CRTC (cathode ray tube controller),
-// encoder and connector. The CRTC determines which framebuffer to read, when
-// to scanout and where to scanout. Encoders converts the stream from the CRTC
-// to the appropriate format for the connector. The connector is the physical
-// connection that monitors connect to.
-//
-// There is no 1:1:1 pairing for these components. It is possible for an encoder
-// to be compatible to multiple CRTCs and each connector can be used with
-// multiple encoders. In addition, it is possible to use one CRTC with multiple
-// connectors such that we can display the same image on multiple monitors.
-//
-// For example, the following configuration shows 2 different screens being
-// initialized separately.
-// ------------- -------------
-// | Connector | | Connector |
-// | HDMI | | VGA |
-// ------------- -------------
-// ^ ^
-// | |
-// ------------- -------------
-// | Encoder1 | | Encoder2 |
-// ------------- -------------
-// ^ ^
-// | |
-// ------------- -------------
-// | CRTC1 | | CRTC2 |
-// ------------- -------------
-//
-// In the following configuration 2 different screens are associated with the
-// same CRTC, so on scanout the same framebuffer will be displayed on both
-// monitors.
-// ------------- -------------
-// | Connector | | Connector |
-// | HDMI | | VGA |
-// ------------- -------------
-// ^ ^
-// | |
-// ------------- -------------
-// | Encoder1 | | Encoder2 |
-// ------------- -------------
-// ^ ^
-// | |
-// ----------------------
-// | CRTC1 |
-// ----------------------
-//
-// Note that it is possible to have more connectors than CRTCs which means that
-// only a subset of connectors can be active independently, showing different
-// framebuffers. Though, in this case, it would be possible to have all
-// connectors active if some use the same CRTC to mirror the display.
-//
-// TODO(dnicoara) Need to have a way to detect events (such as monitor
-// connected or disconnected).
-class GFX_EXPORT HardwareDisplayController {
- public:
- // Controller states. The state transitions will happen from top to bottom.
- enum State {
- // When we allocate a HDCO as a stub. At this point there is no connector
- // and CRTC associated with this device.
- UNASSOCIATED,
-
- // When |SetControllerInfo| is called and the HDCO has the information of
- // the hardware it will control. At this point it knows everything it needs
- // to control the hardware but doesn't have a surface.
- UNINITIALIZED,
-
- // A surface is associated with the HDCO. This means that the controller can
- // potentially display the backing surface to the display. Though the
- // surface framebuffer still needs to be registered with the CRTC.
- SURFACE_INITIALIZED,
-
- // The CRTC now knows about the surface attributes.
- INITIALIZED,
-
- // Error state if any of the initialization steps fail.
- FAILED,
- };
-
- HardwareDisplayController();
-
- ~HardwareDisplayController();
-
- // Set the hardware configuration for this HDCO. Once this is set, the HDCO is
- // responsible for keeping track of the connector and CRTC and cleaning up
- // when it is destroyed.
- void SetControllerInfo(DriWrapper* drm,
- uint32_t connector_id,
- uint32_t crtc_id,
- uint32_t dpms_property_id,
- drmModeModeInfo mode);
-
- // Associate the HDCO with a surface implementation and initialize it.
- bool BindSurfaceToController(scoped_ptr<DriSurface> surface);
-
- // Schedules the |surface_|'s framebuffer to be displayed on the next vsync
- // event. The event will be posted on the graphics card file descriptor |fd_|
- // and it can be read and processed by |drmHandleEvent|. That function can
- // define the callback for the page flip event. A generic data argument will
- // be presented to the callback. We use that argument to pass in the HDCO
- // object the event belongs to.
- //
- // Between this call and the callback, the framebuffer used in this call
- // should not be modified in any way as it would cause screen tearing if the
- // hardware performed the flip. Note that the frontbuffer should also not
- // be modified as it could still be displayed.
- //
- // Note that this function does not block. Also, this function should not be
- // called again before the page flip occurrs.
- //
- // Returns true if the page flip was successfully registered, false otherwise.
- bool SchedulePageFlip();
-
- // Called when the page flip event occurred. The event is provided by the
- // kernel when a VBlank event finished. This allows the controller to
- // update internal state and propagate the update to the surface.
- // The tuple (seconds, useconds) represents the event timestamp. |seconds|
- // represents the number of seconds while |useconds| represents the
- // microseconds (< 1 second) in the timestamp.
- void OnPageFlipEvent(unsigned int frame,
- unsigned int seconds,
- unsigned int useconds);
-
- State get_state() const { return state_; };
-
- int get_fd() const { return drm_->get_fd(); };
-
- const drmModeModeInfo& get_mode() const { return mode_; };
-
- DriSurface* get_surface() const { return surface_.get(); };
-
- uint64_t get_time_of_last_flip() const {
- return time_of_last_flip_;
- };
-
- private:
- // Object containing the connection to the graphics device and wraps the API
- // calls to control it.
- DriWrapper* drm_;
-
- // TODO(dnicoara) Need to allow a CRTC to have multiple connectors.
- uint32_t connector_id_;
-
- uint32_t crtc_id_;
-
- uint32_t dpms_property_id_;
-
- // TODO(dnicoara) Need to store all the modes.
- drmModeModeInfo mode_;
-
- // Saved CRTC state from before we used it. Need it to restore state once we
- // are finished using this device.
- drmModeCrtc* saved_crtc_;
-
- State state_;
-
- scoped_ptr<DriSurface> surface_;
-
- uint64_t time_of_last_flip_;
-
- DISALLOW_COPY_AND_ASSIGN(HardwareDisplayController);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_DRI_HARDWARE_DISPLAY_CONTROLLER_H_
diff --git a/chromium/ui/gfx/ozone/dri/hardware_display_controller_unittest.cc b/chromium/ui/gfx/ozone/dri/hardware_display_controller_unittest.cc
deleted file mode 100644
index 3806b5a157b..00000000000
--- a/chromium/ui/gfx/ozone/dri/hardware_display_controller_unittest.cc
+++ /dev/null
@@ -1,301 +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 "testing/gtest/include/gtest/gtest.h"
-#include "ui/gfx/ozone/dri/dri_skbitmap.h"
-#include "ui/gfx/ozone/dri/dri_surface.h"
-#include "ui/gfx/ozone/dri/dri_wrapper.h"
-#include "ui/gfx/ozone/dri/hardware_display_controller.h"
-
-namespace {
-
-// Create a basic mode for a 6x4 screen.
-const drmModeModeInfo kDefaultMode =
- {0, 6, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, {'\0'}};
-
-// Mock file descriptor ID.
-const int kFd = 3;
-
-// Mock connector ID.
-const uint32_t kConnectorId = 1;
-
-// Mock CRTC ID.
-const uint32_t kCrtcId = 1;
-
-const uint32_t kDPMSPropertyId = 1;
-
-// The real DriWrapper makes actual DRM calls which we can't use in unit tests.
-class MockDriWrapper : public gfx::DriWrapper {
- public:
- MockDriWrapper(int fd) : DriWrapper(""),
- get_crtc_call_count_(0),
- free_crtc_call_count_(0),
- restore_crtc_call_count_(0),
- add_framebuffer_call_count_(0),
- remove_framebuffer_call_count_(0),
- set_crtc_expectation_(true),
- add_framebuffer_expectation_(true),
- page_flip_expectation_(true) {
- fd_ = fd;
- }
-
- virtual ~MockDriWrapper() { fd_ = -1; }
-
- virtual drmModeCrtc* GetCrtc(uint32_t crtc_id) OVERRIDE {
- get_crtc_call_count_++;
- return new drmModeCrtc;
- }
-
- virtual void FreeCrtc(drmModeCrtc* crtc) OVERRIDE {
- free_crtc_call_count_++;
- delete crtc;
- }
-
- virtual bool SetCrtc(uint32_t crtc_id,
- uint32_t framebuffer,
- uint32_t* connectors,
- drmModeModeInfo* mode) OVERRIDE {
- return set_crtc_expectation_;
- }
-
- virtual bool SetCrtc(drmModeCrtc* crtc, uint32_t* connectors) OVERRIDE {
- restore_crtc_call_count_++;
- return true;
- }
-
- virtual bool AddFramebuffer(const drmModeModeInfo& mode,
- uint8_t depth,
- uint8_t bpp,
- uint32_t stride,
- uint32_t handle,
- uint32_t* framebuffer) OVERRIDE {
- add_framebuffer_call_count_++;
- return add_framebuffer_expectation_;
- }
-
- virtual bool RemoveFramebuffer(uint32_t framebuffer) OVERRIDE {
- remove_framebuffer_call_count_++;
- return true;
- }
-
- virtual bool PageFlip(uint32_t crtc_id,
- uint32_t framebuffer,
- void* data) OVERRIDE {
- return page_flip_expectation_;
- }
-
- virtual bool ConnectorSetProperty(uint32_t connector_id,
- uint32_t property_id,
- uint64_t value) OVERRIDE { return true; }
-
- int get_get_crtc_call_count() const {
- return get_crtc_call_count_;
- }
-
- int get_free_crtc_call_count() const {
- return free_crtc_call_count_;
- }
-
- int get_restore_crtc_call_count() const {
- return restore_crtc_call_count_;
- }
-
- int get_add_framebuffer_call_count() const {
- return add_framebuffer_call_count_;
- }
-
- int get_remove_framebuffer_call_count() const {
- return remove_framebuffer_call_count_;
- }
-
- void set_set_crtc_expectation(bool state) {
- set_crtc_expectation_ = state;
- }
-
- void set_add_framebuffer_expectation(bool state) {
- add_framebuffer_expectation_ = state;
- }
-
- void set_page_flip_expectation(bool state) {
- page_flip_expectation_ = state;
- }
-
- private:
- int get_crtc_call_count_;
- int free_crtc_call_count_;
- int restore_crtc_call_count_;
- int add_framebuffer_call_count_;
- int remove_framebuffer_call_count_;
-
- bool set_crtc_expectation_;
- bool add_framebuffer_expectation_;
- bool page_flip_expectation_;
-
- DISALLOW_COPY_AND_ASSIGN(MockDriWrapper);
-};
-
-class MockDriSkBitmap : public gfx::DriSkBitmap {
- public:
- MockDriSkBitmap(int fd) : DriSkBitmap(fd) {}
- virtual ~MockDriSkBitmap() {}
-
- virtual bool Initialize() OVERRIDE {
- return allocPixels();
- }
- private:
- DISALLOW_COPY_AND_ASSIGN(MockDriSkBitmap);
-};
-
-class MockDriSurface : public gfx::DriSurface {
- public:
- MockDriSurface(gfx::HardwareDisplayController* controller)
- : DriSurface(controller) {}
- virtual ~MockDriSurface() {}
-
- private:
- virtual gfx::DriSkBitmap* CreateBuffer() OVERRIDE {
- return new MockDriSkBitmap(kFd);
- }
- DISALLOW_COPY_AND_ASSIGN(MockDriSurface);
-};
-
-} // namespace
-
-class HardwareDisplayControllerTest : public testing::Test {
- public:
- HardwareDisplayControllerTest() {}
- virtual ~HardwareDisplayControllerTest() {}
-
- virtual void SetUp() OVERRIDE;
- virtual void TearDown() OVERRIDE;
- protected:
- scoped_ptr<gfx::HardwareDisplayController> controller_;
- scoped_ptr<MockDriWrapper> drm_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(HardwareDisplayControllerTest);
-};
-
-void HardwareDisplayControllerTest::SetUp() {
- controller_.reset(new gfx::HardwareDisplayController());
- drm_.reset(new MockDriWrapper(kFd));
-}
-
-void HardwareDisplayControllerTest::TearDown() {
- controller_.reset();
- drm_.reset();
-}
-
-TEST_F(HardwareDisplayControllerTest, CheckInitialState) {
- EXPECT_EQ(gfx::HardwareDisplayController::UNASSOCIATED,
- controller_->get_state());
-}
-
-TEST_F(HardwareDisplayControllerTest,
- CheckStateAfterControllerIsInitialized) {
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
-
- EXPECT_EQ(1, drm_->get_get_crtc_call_count());
- EXPECT_EQ(gfx::HardwareDisplayController::UNINITIALIZED,
- controller_->get_state());
-}
-
-TEST_F(HardwareDisplayControllerTest, CheckStateAfterSurfaceIsBound) {
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
- scoped_ptr<gfx::DriSurface> surface(
- new MockDriSurface(controller_.get()));
-
- EXPECT_TRUE(surface->Initialize());
- EXPECT_TRUE(controller_->BindSurfaceToController(surface.Pass()));
-
- EXPECT_EQ(2, drm_->get_add_framebuffer_call_count());
- EXPECT_EQ(gfx::HardwareDisplayController::SURFACE_INITIALIZED,
- controller_->get_state());
-}
-
-TEST_F(HardwareDisplayControllerTest, CheckStateIfBindingFails) {
- drm_->set_add_framebuffer_expectation(false);
-
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
- scoped_ptr<gfx::DriSurface> surface(
- new MockDriSurface(controller_.get()));
-
- EXPECT_TRUE(surface->Initialize());
- EXPECT_FALSE(controller_->BindSurfaceToController(surface.Pass()));
-
- EXPECT_EQ(1, drm_->get_add_framebuffer_call_count());
- EXPECT_EQ(gfx::HardwareDisplayController::FAILED,
- controller_->get_state());
-}
-
-TEST_F(HardwareDisplayControllerTest, CheckStateAfterPageFlip) {
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
- scoped_ptr<gfx::DriSurface> surface(
- new MockDriSurface(controller_.get()));
-
- EXPECT_TRUE(surface->Initialize());
- EXPECT_TRUE(controller_->BindSurfaceToController(surface.Pass()));
-
- controller_->SchedulePageFlip();
-
- EXPECT_EQ(gfx::HardwareDisplayController::INITIALIZED,
- controller_->get_state());
-}
-
-TEST_F(HardwareDisplayControllerTest, CheckStateIfModesetFails) {
- drm_->set_set_crtc_expectation(false);
-
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
- scoped_ptr<gfx::DriSurface> surface(
- new MockDriSurface(controller_.get()));
-
- EXPECT_TRUE(surface->Initialize());
- EXPECT_TRUE(controller_->BindSurfaceToController(surface.Pass()));
-
- controller_->SchedulePageFlip();
-
- EXPECT_EQ(gfx::HardwareDisplayController::FAILED,
- controller_->get_state());
-}
-
-TEST_F(HardwareDisplayControllerTest, CheckStateIfPageFlipFails) {
- drm_->set_page_flip_expectation(false);
-
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
- scoped_ptr<gfx::DriSurface> surface(
- new MockDriSurface(controller_.get()));
-
- EXPECT_TRUE(surface->Initialize());
- EXPECT_TRUE(controller_->BindSurfaceToController(surface.Pass()));
-
- controller_->SchedulePageFlip();
-
- EXPECT_EQ(gfx::HardwareDisplayController::FAILED,
- controller_->get_state());
-}
-
-TEST_F(HardwareDisplayControllerTest, CheckProperDestruction) {
- controller_->SetControllerInfo(
- drm_.get(), kConnectorId, kCrtcId, kDPMSPropertyId, kDefaultMode);
- scoped_ptr<gfx::DriSurface> surface(
- new MockDriSurface(controller_.get()));
-
- EXPECT_TRUE(surface->Initialize());
- EXPECT_TRUE(controller_->BindSurfaceToController(surface.Pass()));
-
- EXPECT_EQ(gfx::HardwareDisplayController::SURFACE_INITIALIZED,
- controller_->get_state());
-
- controller_.reset();
-
- EXPECT_EQ(2, drm_->get_remove_framebuffer_call_count());
- EXPECT_EQ(1, drm_->get_restore_crtc_call_count());
- EXPECT_EQ(1, drm_->get_free_crtc_call_count());
-}
diff --git a/chromium/ui/gfx/ozone/impl/file_surface_factory.cc b/chromium/ui/gfx/ozone/impl/file_surface_factory.cc
deleted file mode 100644
index 9d34f7f95a3..00000000000
--- a/chromium/ui/gfx/ozone/impl/file_surface_factory.cc
+++ /dev/null
@@ -1,96 +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/ozone/impl/file_surface_factory.h"
-
-#include "base/bind.h"
-#include "base/file_util.h"
-#include "base/location.h"
-#include "base/stl_util.h"
-#include "base/threading/worker_pool.h"
-#include "third_party/skia/include/core/SkBitmapDevice.h"
-#include "third_party/skia/include/core/SkDevice.h"
-#include "ui/gfx/codec/png_codec.h"
-
-namespace {
-
-void WriteDataToFile(const base::FilePath& location,
- const SkBitmap& bitmap) {
- std::vector<unsigned char> png_data;
- gfx::PNGCodec::FastEncodeBGRASkBitmap(bitmap, true, &png_data);
- file_util::WriteFile(location,
- (char*)vector_as_array(&png_data),
- png_data.size());
-}
-
-}
-
-namespace gfx {
-
-FileSurfaceFactory::FileSurfaceFactory(
- const base::FilePath& dump_location)
- : location_(dump_location) {
- CHECK(!base::DirectoryExists(location_))
- << "Location cannot be a directory (" << location_.value() << ")";
- CHECK(!base::PathExists(location_) || base::PathIsWritable(location_));
-}
-
-FileSurfaceFactory::~FileSurfaceFactory() {}
-
-SurfaceFactoryOzone::HardwareState
-FileSurfaceFactory::InitializeHardware() {
- return INITIALIZED;
-}
-
-void FileSurfaceFactory::ShutdownHardware() {
-}
-
-AcceleratedWidget FileSurfaceFactory::GetAcceleratedWidget() {
- return 1;
-}
-
-AcceleratedWidget FileSurfaceFactory::RealizeAcceleratedWidget(
- AcceleratedWidget widget) {
- return 1;
-}
-
-bool FileSurfaceFactory::LoadEGLGLES2Bindings(
- AddGLLibraryCallback add_gl_library,
- SetGLGetProcAddressProcCallback set_gl_get_proc_address) {
- return false;
-}
-
-bool FileSurfaceFactory::AttemptToResizeAcceleratedWidget(
- AcceleratedWidget widget,
- const Rect& bounds) {
- device_ = skia::AdoptRef(new SkBitmapDevice(SkBitmap::kARGB_8888_Config,
- bounds.width(),
- bounds.height()));
- canvas_ = skia::AdoptRef(new SkCanvas(device_.get()));
- return true;
-}
-
-bool FileSurfaceFactory::SchedulePageFlip(AcceleratedWidget widget) {
- SkBitmap bitmap;
- bitmap.setConfig(SkBitmap::kARGB_8888_Config,
- device_->width(),
- device_->height());
-
- if (canvas_->readPixels(&bitmap, 0, 0)) {
- base::WorkerPool::PostTask(FROM_HERE,
- base::Bind(&WriteDataToFile, location_, bitmap),
- true);
- }
- return true;
-}
-
-SkCanvas* FileSurfaceFactory::GetCanvasForWidget(AcceleratedWidget w) {
- return canvas_.get();
-}
-
-VSyncProvider* FileSurfaceFactory::GetVSyncProvider(AcceleratedWidget w) {
- return NULL;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/impl/file_surface_factory.h b/chromium/ui/gfx/ozone/impl/file_surface_factory.h
deleted file mode 100644
index 19f1c946a33..00000000000
--- a/chromium/ui/gfx/ozone/impl/file_surface_factory.h
+++ /dev/null
@@ -1,49 +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_OZONE_IMPL_FILE_SURFACE_FACTORY_H_
-#define UI_GFX_OZONE_IMPL_FILE_SURFACE_FACTORY_H_
-
-#include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/ozone/surface_factory_ozone.h"
-#include "ui/gfx/skia_util.h"
-
-class SkBitmapDevice;
-class SkCanvas;
-
-namespace gfx {
-
-class GFX_EXPORT FileSurfaceFactory : public SurfaceFactoryOzone {
- public:
- explicit FileSurfaceFactory(const base::FilePath& dump_location);
- virtual ~FileSurfaceFactory();
-
- private:
- // SurfaceFactoryOzone:
- virtual HardwareState InitializeHardware() OVERRIDE;
- virtual void ShutdownHardware() OVERRIDE;
- virtual AcceleratedWidget GetAcceleratedWidget() OVERRIDE;
- virtual AcceleratedWidget RealizeAcceleratedWidget(
- AcceleratedWidget widget) OVERRIDE;
- virtual bool LoadEGLGLES2Bindings(
- AddGLLibraryCallback add_gl_library,
- SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE;
- virtual bool AttemptToResizeAcceleratedWidget(AcceleratedWidget widget,
- const Rect& bounds) OVERRIDE;
- virtual bool SchedulePageFlip(AcceleratedWidget widget) OVERRIDE;
- virtual SkCanvas* GetCanvasForWidget(AcceleratedWidget widget) OVERRIDE;
- virtual VSyncProvider* GetVSyncProvider(AcceleratedWidget widget) OVERRIDE;
-
- base::FilePath location_;
- skia::RefPtr<SkBitmapDevice> device_;
- skia::RefPtr<SkCanvas> canvas_;
-
- DISALLOW_COPY_AND_ASSIGN(FileSurfaceFactory);
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_IMPL_FILE_SURFACE_FACTORY_H_
diff --git a/chromium/ui/gfx/ozone/surface_factory_ozone.cc b/chromium/ui/gfx/ozone/surface_factory_ozone.cc
deleted file mode 100644
index ea8e2f1a0b2..00000000000
--- a/chromium/ui/gfx/ozone/surface_factory_ozone.cc
+++ /dev/null
@@ -1,92 +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 "ui/gfx/ozone/surface_factory_ozone.h"
-
-#include <stdlib.h>
-
-#include "base/command_line.h"
-
-namespace gfx {
-
-// static
-SurfaceFactoryOzone* SurfaceFactoryOzone::impl_ = NULL;
-
-class SurfaceFactoryOzoneStub : public SurfaceFactoryOzone {
- public:
- SurfaceFactoryOzoneStub() {}
- virtual ~SurfaceFactoryOzoneStub() {}
-
- virtual HardwareState InitializeHardware() OVERRIDE { return INITIALIZED; }
- virtual void ShutdownHardware() OVERRIDE {}
- virtual gfx::AcceleratedWidget GetAcceleratedWidget() OVERRIDE { return 0; }
- virtual gfx::AcceleratedWidget RealizeAcceleratedWidget(
- gfx::AcceleratedWidget w) OVERRIDE {
- return 0;
- }
- virtual bool LoadEGLGLES2Bindings(
- AddGLLibraryCallback add_gl_library,
- SetGLGetProcAddressProcCallback set_gl_get_proc_address) OVERRIDE {
- return true;
- }
- virtual bool AttemptToResizeAcceleratedWidget(
- gfx::AcceleratedWidget w,
- const gfx::Rect& bounds) OVERRIDE {
- return false;
- }
- virtual gfx::VSyncProvider* GetVSyncProvider(
- gfx::AcceleratedWidget w) OVERRIDE {
- return NULL;
- }
-};
-
-SurfaceFactoryOzone::SurfaceFactoryOzone() {
-}
-
-SurfaceFactoryOzone::~SurfaceFactoryOzone() {
-}
-
-SurfaceFactoryOzone* SurfaceFactoryOzone::GetInstance() {
- CHECK(impl_) << "No SurfaceFactoryOzone implementation set.";
- return impl_;
-}
-
-void SurfaceFactoryOzone::SetInstance(SurfaceFactoryOzone* impl) {
- impl_ = impl;
-}
-
-const char* SurfaceFactoryOzone::DefaultDisplaySpec() {
- char* envvar = getenv("ASH_DISPLAY_SPEC");
- if (envvar)
- return envvar;
- return "720x1280*2";
-}
-
-gfx::Screen* SurfaceFactoryOzone::CreateDesktopScreen() {
- return NULL;
-}
-
-intptr_t SurfaceFactoryOzone::GetNativeDisplay() {
- return 0;
-}
-
-bool SurfaceFactoryOzone::SchedulePageFlip(gfx::AcceleratedWidget w) {
- return true;
-}
-
-SkCanvas* SurfaceFactoryOzone::GetCanvasForWidget(gfx::AcceleratedWidget w) {
- return NULL;
-}
-
-const int32* SurfaceFactoryOzone::GetEGLSurfaceProperties(
- const int32* desired_attributes) {
- return desired_attributes;
-}
-
-// static
-SurfaceFactoryOzone* SurfaceFactoryOzone::CreateTestHelper() {
- return new SurfaceFactoryOzoneStub;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/ozone/surface_factory_ozone.h b/chromium/ui/gfx/ozone/surface_factory_ozone.h
deleted file mode 100644
index c09a65ff8c7..00000000000
--- a/chromium/ui/gfx/ozone/surface_factory_ozone.h
+++ /dev/null
@@ -1,147 +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.
-
-#ifndef UI_GFX_OZONE_SURFACE_LNUX_FACTORY_OZONE_H_
-#define UI_GFX_OZONE_SURFACE_LNUX_FACTORY_OZONE_H_
-
-#include "base/callback.h"
-#include "base/native_library.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/native_widget_types.h"
-#include "ui/gfx/rect.h"
-
-class SkCanvas;
-
-namespace gfx {
-class Screen;
-class VSyncProvider;
-
-// The Ozone interface allows external implementations to hook into Chromium to
-// provide a system specific implementation. The Ozone interface supports two
-// drawing modes: 1) accelerated drawing through EGL and 2) software drawing
-// through Skia.
-//
-// The following functionality is specific to the drawing mode and may not have
-// any meaningful implementation in the other mode. An implementation must
-// provide functionality for at least one mode.
-//
-// 1) Accelerated Drawing (EGL path):
-//
-// The following functions are specific to EGL:
-// - GetNativeDisplay
-// - LoadEGLGLES2Bindings
-// - GetEGLSurfaceProperties (optional if the properties match the default
-// Chromium ones).
-//
-// 2) Software Drawing (Skia):
-//
-// The following function is specific to the software path:
-// - GetCanvasForWidget
-//
-// The accelerated path can optionally provide support for the software drawing
-// path.
-//
-// The remaining functions are not covered since they are needed in both drawing
-// modes (See comments bellow for descriptions).
-class GFX_EXPORT SurfaceFactoryOzone {
- public:
- // Describes the state of the hardware after initialization.
- enum HardwareState {
- UNINITIALIZED,
- INITIALIZED,
- FAILED,
- };
-
- typedef void*(*GLGetProcAddressProc)(const char* name);
- typedef base::Callback<void(base::NativeLibrary)> AddGLLibraryCallback;
- typedef base::Callback<void(GLGetProcAddressProc)>
- SetGLGetProcAddressProcCallback;
-
- SurfaceFactoryOzone();
- virtual ~SurfaceFactoryOzone();
-
- // Returns the instance
- static SurfaceFactoryOzone* GetInstance();
-
- // Returns a display spec as in |CreateDisplayFromSpec| for the default
- // native surface.
- virtual const char* DefaultDisplaySpec();
-
- // Sets the implementation delegate. Ownership is retained by the caller.
- static void SetInstance(SurfaceFactoryOzone* impl);
-
- // TODO(rjkroege): decide how to separate screen/display stuff from SFOz
- // This method implements gfx::Screen, particularly useful in Desktop Aura.
- virtual gfx::Screen* CreateDesktopScreen();
-
- // Configures the display hardware. Must be called from within the GPU
- // process before the sandbox has been activated.
- virtual HardwareState InitializeHardware() = 0;
-
- // Cleans up display hardware state. Call this from within the GPU process.
- // This method must be safe to run inside of the sandbox.
- virtual void ShutdownHardware() = 0;
-
- // Returns native platform display handle. This is used to obtain the EGL
- // display connection for the native display.
- virtual intptr_t GetNativeDisplay();
-
- // Obtains an AcceleratedWidget backed by a native Linux framebuffer.
- // The returned AcceleratedWidget is an opaque token that must realized
- // before it can be used to create a GL surface.
- virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0;
-
- // Realizes an AcceleratedWidget so that the returned AcceleratedWidget
- // can be used to to create a GLSurface. This method may only be called in
- // a process that has a valid GL context.
- virtual gfx::AcceleratedWidget RealizeAcceleratedWidget(
- gfx::AcceleratedWidget w) = 0;
-
- // Sets up GL bindings for the native surface. Takes two callback parameters
- // that allow Ozone to register the GL bindings.
- virtual bool LoadEGLGLES2Bindings(
- AddGLLibraryCallback add_gl_library,
- SetGLGetProcAddressProcCallback set_gl_get_proc_address) = 0;
-
- // If possible attempts to resize the given AcceleratedWidget instance and if
- // a resize action was performed returns true, otherwise false (native
- // hardware may only support a single fixed size).
- virtual bool AttemptToResizeAcceleratedWidget(
- gfx::AcceleratedWidget w,
- const gfx::Rect& bounds) = 0;
-
- // Called after the appropriate GL swap buffers command. Used if extra work
- // is needed to perform the actual buffer swap.
- virtual bool SchedulePageFlip(gfx::AcceleratedWidget w);
-
- // Returns a SkCanvas for the backing buffers. Drawing to the canvas will draw
- // to the native surface. The canvas is intended for use when no EGL
- // acceleration is possible. Its implementation is optional when an EGL
- // backend is provided for rendering.
- virtual SkCanvas* GetCanvasForWidget(gfx::AcceleratedWidget w);
-
- // Returns a gfx::VsyncProvider for the provided AcceleratedWidget. Note
- // that this may be called after we have entered the sandbox so if there are
- // operations (e.g. opening a file descriptor providing vsync events) that
- // must be done outside of the sandbox, they must have been completed
- // in InitializeHardware. Returns NULL on error.
- virtual gfx::VSyncProvider* GetVSyncProvider(gfx::AcceleratedWidget w) = 0;
-
- // Returns an array of EGL properties, which can be used in any EGL function
- // used to select a display configuration. Note that all properties should be
- // immediately followed by the corresponding desired value and array should be
- // terminated with EGL_NONE. Ownership of the array is not transferred to
- // caller. desired_list contains list of desired EGL properties and values.
- virtual const int32* GetEGLSurfaceProperties(const int32* desired_list);
-
- // Create a default SufaceFactoryOzone implementation useful for tests.
- static SurfaceFactoryOzone* CreateTestHelper();
-
- private:
- static SurfaceFactoryOzone* impl_; // not owned
-};
-
-} // namespace gfx
-
-#endif // UI_GFX_OZONE_SURFACE_LNUX_FACTORY_OZONE_H_
diff --git a/chromium/ui/gfx/pango_util.cc b/chromium/ui/gfx/pango_util.cc
index 1f8ac261b59..56503c6a01f 100644
--- a/chromium/ui/gfx/pango_util.cc
+++ b/chromium/ui/gfx/pango_util.cc
@@ -23,10 +23,6 @@
#include "ui/gfx/rect.h"
#include "ui/gfx/text_utils.h"
-#if defined(TOOLKIT_GTK)
-#include <gdk/gdk.h>
-#endif
-
namespace gfx {
namespace {
@@ -116,12 +112,8 @@ float GetPixelsInPoint() {
} // namespace
PangoContext* GetPangoContext() {
-#if defined(TOOLKIT_GTK)
- return gdk_pango_context_get();
-#else
PangoFontMap* font_map = pango_cairo_font_map_get_default();
return pango_font_map_create_context(font_map);
-#endif
}
double GetPangoResolution() {
@@ -211,7 +203,7 @@ static void SetupPangoLayoutWithoutFont(
// Set text and accelerator character if needed.
if (flags & Canvas::SHOW_PREFIX) {
// Escape the text string to be used as markup.
- std::string utf8 = UTF16ToUTF8(text);
+ std::string utf8 = base::UTF16ToUTF8(text);
gchar* escaped_text = g_markup_escape_text(utf8.c_str(), utf8.size());
pango_layout_set_markup_with_accel(layout,
escaped_text,
@@ -229,9 +221,9 @@ static void SetupPangoLayoutWithoutFont(
RemoveAcceleratorChar(text,
static_cast<base::char16>(kAcceleratorChar),
NULL, NULL);
- utf8 = UTF16ToUTF8(accelerator_removed);
+ utf8 = base::UTF16ToUTF8(accelerator_removed);
} else {
- utf8 = UTF16ToUTF8(text);
+ utf8 = base::UTF16ToUTF8(text);
}
pango_layout_set_text(layout, utf8.data(), utf8.size());
diff --git a/chromium/ui/gfx/path.h b/chromium/ui/gfx/path.h
index 257a65c0102..b0f07279c7f 100644
--- a/chromium/ui/gfx/path.h
+++ b/chromium/ui/gfx/path.h
@@ -32,7 +32,7 @@ class GFX_EXPORT Path : public SkPath {
~Path();
-#if defined(USE_AURA) || defined(OS_WIN) || defined(USE_X11)
+#if defined(USE_AURA) || defined(USE_X11)
// Creates a NativeRegion from the path. The caller is responsible for freeing
// resources used by this region. This only supports polygon paths.
NativeRegion CreateNativeRegion() const;
diff --git a/chromium/ui/gfx/path_gtk.cc b/chromium/ui/gfx/path_gtk.cc
deleted file mode 100644
index 99dad2be43b..00000000000
--- a/chromium/ui/gfx/path_gtk.cc
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2011 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/path.h"
-
-#include <gdk/gdk.h>
-
-#include "base/command_line.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace gfx {
-
-GdkRegion* Path::CreateNativeRegion() const {
- int point_count = getPoints(NULL, 0);
- if (point_count <= 1) {
- // NOTE: ideally this would return gdk_empty_region, but that returns a
- // region with nothing in it.
- return NULL;
- }
-
- scoped_ptr<SkPoint[]> points(new SkPoint[point_count]);
- getPoints(points.get(), point_count);
-
- scoped_ptr<GdkPoint[]> gdk_points(new GdkPoint[point_count]);
- for (int i = 0; i < point_count; ++i) {
- gdk_points[i].x = SkScalarRound(points[i].fX);
- gdk_points[i].y = SkScalarRound(points[i].fY);
- }
-
- return gdk_region_polygon(gdk_points.get(), point_count, GDK_EVEN_ODD_RULE);
-}
-
-// static
-NativeRegion Path::IntersectRegions(NativeRegion r1, NativeRegion r2) {
- GdkRegion* copy = gdk_region_copy(r1);
- gdk_region_intersect(copy, r2);
- return copy;
-}
-
-// static
-NativeRegion Path::CombineRegions(NativeRegion r1, NativeRegion r2) {
- GdkRegion* copy = gdk_region_copy(r1);
- gdk_region_union(copy, r2);
- return copy;
-}
-
-// static
-NativeRegion Path::SubtractRegion(NativeRegion r1, NativeRegion r2) {
- GdkRegion* copy = gdk_region_copy(r1);
- gdk_region_subtract(copy, r2);
- return copy;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/path_win.cc b/chromium/ui/gfx/path_win.cc
index bce62ac849b..b28ea7a2c7b 100644
--- a/chromium/ui/gfx/path_win.cc
+++ b/chromium/ui/gfx/path_win.cc
@@ -30,8 +30,8 @@ HRGN CreateHRGNFromSkPath(const SkPath& path) {
path.getPoints(points.get(), point_count);
scoped_ptr<POINT[]> windows_points(new POINT[point_count]);
for (int i = 0; i < point_count; ++i) {
- windows_points[i].x = SkScalarRound(points[i].fX);
- windows_points[i].y = SkScalarRound(points[i].fY);
+ windows_points[i].x = SkScalarRoundToInt(points[i].fX);
+ windows_points[i].y = SkScalarRoundToInt(points[i].fY);
}
return ::CreatePolygonRgn(windows_points.get(), point_count, ALTERNATE);
diff --git a/chromium/ui/gfx/path_x11.cc b/chromium/ui/gfx/path_x11.cc
index 2fe764fbd4c..caea2ec12e6 100644
--- a/chromium/ui/gfx/path_x11.cc
+++ b/chromium/ui/gfx/path_x11.cc
@@ -4,6 +4,8 @@
#include "ui/gfx/path_x11.h"
+#include <X11/Xlib.h>
+#include <X11/Xregion.h>
#include <X11/Xutil.h>
#include "base/memory/scoped_ptr.h"
@@ -33,8 +35,8 @@ Region CreateRegionFromSkPath(const SkPath& path) {
path.getPoints(points.get(), point_count);
scoped_ptr<XPoint[]> x11_points(new XPoint[point_count]);
for (int i = 0; i < point_count; ++i) {
- x11_points[i].x = SkScalarRound(points[i].fX);
- x11_points[i].y = SkScalarRound(points[i].fY);
+ x11_points[i].x = SkScalarRoundToInt(points[i].fX);
+ x11_points[i].y = SkScalarRoundToInt(points[i].fY);
}
return XPolygonRegion(x11_points.get(), point_count, EvenOddRule);
diff --git a/chromium/ui/gfx/path_x11.h b/chromium/ui/gfx/path_x11.h
index c6e750742ec..6e3a1568293 100644
--- a/chromium/ui/gfx/path_x11.h
+++ b/chromium/ui/gfx/path_x11.h
@@ -5,14 +5,13 @@
#ifndef UI_GFX_PATH_X11_H_
#define UI_GFX_PATH_X11_H_
-#include <X11/Xlib.h>
-#include <X11/Xregion.h>
-
#include "ui/gfx/gfx_export.h"
class SkPath;
class SkRegion;
+typedef struct _XRegion REGION;
+
namespace gfx {
// Creates a new REGION given |region|. The caller is responsible for destroying
diff --git a/chromium/ui/gfx/platform_font.h b/chromium/ui/gfx/platform_font.h
index bf470983e12..27f39b751a9 100644
--- a/chromium/ui/gfx/platform_font.h
+++ b/chromium/ui/gfx/platform_font.h
@@ -45,13 +45,6 @@ class GFX_EXPORT PlatformFont : public base::RefCounted<PlatformFont> {
// Returns the cap height of the font.
virtual int GetCapHeight() const = 0;
- // Returns the average character width for the font.
- virtual int GetAverageCharacterWidth() const = 0;
-
- // Returns the number of horizontal pixels needed to display the specified
- // string.
- virtual int GetStringWidth(const base::string16& text) const = 0;
-
// Returns the expected number of horizontal pixels needed to display the
// specified length of characters. Call GetStringWidth() to retrieve the
// actual number.
diff --git a/chromium/ui/gfx/platform_font_ios.h b/chromium/ui/gfx/platform_font_ios.h
index ed93a6b6e66..3323f820c45 100644
--- a/chromium/ui/gfx/platform_font_ios.h
+++ b/chromium/ui/gfx/platform_font_ios.h
@@ -21,8 +21,6 @@ class PlatformFontIOS : public PlatformFont {
virtual int GetHeight() const OVERRIDE;
virtual int GetBaseline() const OVERRIDE;
virtual int GetCapHeight() const OVERRIDE;
- virtual int GetAverageCharacterWidth() const OVERRIDE;
- virtual int GetStringWidth(const base::string16& text) const OVERRIDE;
virtual int GetExpectedTextWidth(int length) const OVERRIDE;
virtual int GetStyle() const OVERRIDE;
virtual std::string GetFontName() const OVERRIDE;
diff --git a/chromium/ui/gfx/platform_font_ios.mm b/chromium/ui/gfx/platform_font_ios.mm
index 32dcca4e395..aba239b732d 100644
--- a/chromium/ui/gfx/platform_font_ios.mm
+++ b/chromium/ui/gfx/platform_font_ios.mm
@@ -55,15 +55,6 @@ int PlatformFontIOS::GetCapHeight() const {
return cap_height_;
}
-int PlatformFontIOS::GetAverageCharacterWidth() const {
- return average_width_;
-}
-
-int PlatformFontIOS::GetStringWidth(const base::string16& text) const {
- NSString* ns_text = base::SysUTF16ToNSString(text);
- return [ns_text sizeWithFont:GetNativeFont()].width;
-}
-
int PlatformFontIOS::GetExpectedTextWidth(int length) const {
return length * average_width_;
}
diff --git a/chromium/ui/gfx/platform_font_mac.h b/chromium/ui/gfx/platform_font_mac.h
index 2f5f8deb3fe..8c469882ff1 100644
--- a/chromium/ui/gfx/platform_font_mac.h
+++ b/chromium/ui/gfx/platform_font_mac.h
@@ -23,8 +23,6 @@ class PlatformFontMac : public PlatformFont {
virtual int GetHeight() const OVERRIDE;
virtual int GetBaseline() const OVERRIDE;
virtual int GetCapHeight() const OVERRIDE;
- virtual int GetAverageCharacterWidth() const OVERRIDE;
- virtual int GetStringWidth(const base::string16& text) const OVERRIDE;
virtual int GetExpectedTextWidth(int length) const OVERRIDE;
virtual int GetStyle() const OVERRIDE;
virtual std::string GetFontName() const OVERRIDE;
diff --git a/chromium/ui/gfx/platform_font_mac.mm b/chromium/ui/gfx/platform_font_mac.mm
index 877507eb47b..53e3013170c 100644
--- a/chromium/ui/gfx/platform_font_mac.mm
+++ b/chromium/ui/gfx/platform_font_mac.mm
@@ -105,15 +105,6 @@ int PlatformFontMac::GetCapHeight() const {
return cap_height_;
}
-int PlatformFontMac::GetAverageCharacterWidth() const {
- return average_width_;
-}
-
-int PlatformFontMac::GetStringWidth(const base::string16& text) const {
- return Canvas::GetStringWidth(text,
- Font(const_cast<PlatformFontMac*>(this)));
-}
-
int PlatformFontMac::GetExpectedTextWidth(int length) const {
return length * average_width_;
}
diff --git a/chromium/ui/gfx/platform_font_mac_unittest.mm b/chromium/ui/gfx/platform_font_mac_unittest.mm
index 088d4a9bd2d..2584cb50d31 100644
--- a/chromium/ui/gfx/platform_font_mac_unittest.mm
+++ b/chromium/ui/gfx/platform_font_mac_unittest.mm
@@ -12,20 +12,20 @@ TEST(PlatformFontMacTest, DeriveFont) {
gfx::Font base_font("Helvetica", 13);
// Bold
- gfx::Font bold_font(base_font.DeriveFont(0, gfx::Font::BOLD));
+ gfx::Font bold_font(base_font.Derive(0, gfx::Font::BOLD));
NSFontTraitMask traits = [[NSFontManager sharedFontManager]
traitsOfFont:bold_font.GetNativeFont()];
EXPECT_EQ(NSBoldFontMask, traits);
// Italic
- gfx::Font italic_font(base_font.DeriveFont(0, gfx::Font::ITALIC));
+ gfx::Font italic_font(base_font.Derive(0, gfx::Font::ITALIC));
traits = [[NSFontManager sharedFontManager]
traitsOfFont:italic_font.GetNativeFont()];
EXPECT_EQ(NSItalicFontMask, traits);
// Bold italic
- gfx::Font bold_italic_font(base_font.DeriveFont(0, gfx::Font::BOLD |
- gfx::Font::ITALIC));
+ gfx::Font bold_italic_font(base_font.Derive(
+ 0, gfx::Font::BOLD | gfx::Font::ITALIC));
traits = [[NSFontManager sharedFontManager]
traitsOfFont:bold_italic_font.GetNativeFont()];
EXPECT_EQ(static_cast<NSFontTraitMask>(NSBoldFontMask | NSItalicFontMask),
diff --git a/chromium/ui/gfx/platform_font_pango.cc b/chromium/ui/gfx/platform_font_pango.cc
index db1d7dce351..efc940bd186 100644
--- a/chromium/ui/gfx/platform_font_pango.cc
+++ b/chromium/ui/gfx/platform_font_pango.cc
@@ -19,12 +19,10 @@
#include "third_party/skia/include/core/SkTypeface.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/font.h"
+#include "ui/gfx/font_list.h"
+#include "ui/gfx/linux_font_delegate.h"
#include "ui/gfx/pango_util.h"
-
-#if defined(TOOLKIT_GTK)
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
-#endif
+#include "ui/gfx/text_utils.h"
namespace {
@@ -184,23 +182,7 @@ int PlatformFontPango::GetBaseline() const {
}
int PlatformFontPango::GetCapHeight() const {
- // Return the ascent as an approximation because Pango doesn't support cap
- // height.
- // TODO(yukishiino): Come up with a better approximation of cap height, or
- // support cap height metrics. Another option is to have a hard-coded table
- // of cap height for major fonts used in Chromium/Chrome.
- // See http://crbug.com/249507
- return ascent_pixels_;
-}
-
-int PlatformFontPango::GetAverageCharacterWidth() const {
- const_cast<PlatformFontPango*>(this)->InitPangoMetrics();
- return SkScalarRound(average_width_pixels_);
-}
-
-int PlatformFontPango::GetStringWidth(const base::string16& text) const {
- return Canvas::GetStringWidth(text,
- Font(const_cast<PlatformFontPango*>(this)));
+ return cap_height_pixels_;
}
int PlatformFontPango::GetExpectedTextWidth(int length) const {
@@ -269,31 +251,19 @@ PlatformFontPango::~PlatformFontPango() {}
// static
std::string PlatformFontPango::GetDefaultFont() {
-#if !defined(TOOLKIT_GTK)
#if defined(OS_CHROMEOS)
// Font name must have been provided by way of SetDefaultFontDescription().
CHECK(default_font_description_);
return *default_font_description_;
#else
+ const gfx::LinuxFontDelegate* delegate = gfx::LinuxFontDelegate::instance();
+ if (delegate)
+ return delegate->GetDefaultFontName();
+
return "sans 10";
#endif // defined(OS_CHROMEOS)
-#else
- GtkSettings* settings = gtk_settings_get_default();
-
- gchar* font_name = NULL;
- g_object_get(settings, "gtk-font-name", &font_name, NULL);
-
- // Temporary CHECK for helping track down
- // http://code.google.com/p/chromium/issues/detail?id=12530
- CHECK(font_name) << " Unable to get gtk-font-name for default font.";
-
- std::string default_font = std::string(font_name);
- g_free(font_name);
- return default_font;
-#endif // !defined(TOOLKIT_GTK)
}
-
void PlatformFontPango::InitWithNameAndSize(const std::string& font_name,
int font_size) {
DCHECK_GT(font_size, 0);
@@ -338,8 +308,9 @@ void PlatformFontPango::InitWithTypefaceNameSizeAndStyle(
PaintSetup(&paint);
paint.getFontMetrics(&metrics);
- ascent_pixels_ = SkScalarCeil(-metrics.fAscent);
- height_pixels_ = ascent_pixels_ + SkScalarCeil(metrics.fDescent);
+ ascent_pixels_ = SkScalarCeilToInt(-metrics.fAscent);
+ height_pixels_ = ascent_pixels_ + SkScalarCeilToInt(metrics.fDescent);
+ cap_height_pixels_ = SkScalarCeilToInt(metrics.fCapHeight);
}
void PlatformFontPango::InitFromPlatformFont(const PlatformFontPango* other) {
@@ -349,6 +320,7 @@ void PlatformFontPango::InitFromPlatformFont(const PlatformFontPango* other) {
style_ = other->style_;
height_pixels_ = other->height_pixels_;
ascent_pixels_ = other->ascent_pixels_;
+ cap_height_pixels_ = other->cap_height_pixels_;
pango_metrics_inited_ = other->pango_metrics_inited_;
average_width_pixels_ = other->average_width_pixels_;
underline_position_pixels_ = other->underline_position_pixels_;
@@ -392,7 +364,9 @@ void PlatformFontPango::InitPangoMetrics() {
// Yes, this is how Microsoft recommends calculating the dialog unit
// conversions.
const int text_width_pixels = GetStringWidth(
- ASCIIToUTF16("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
+ base::ASCIIToUTF16(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"),
+ FontList(Font(this)));
const double dialog_units_pixels = (text_width_pixels / 26 + 1) / 2;
average_width_pixels_ = std::min(pango_width_pixels, dialog_units_pixels);
}
diff --git a/chromium/ui/gfx/platform_font_pango.h b/chromium/ui/gfx/platform_font_pango.h
index 739a633aa47..548b3ac56e7 100644
--- a/chromium/ui/gfx/platform_font_pango.h
+++ b/chromium/ui/gfx/platform_font_pango.h
@@ -50,8 +50,6 @@ class GFX_EXPORT PlatformFontPango : public PlatformFont {
virtual int GetHeight() const OVERRIDE;
virtual int GetBaseline() const OVERRIDE;
virtual int GetCapHeight() const OVERRIDE;
- virtual int GetAverageCharacterWidth() const OVERRIDE;
- virtual int GetStringWidth(const base::string16& text) const OVERRIDE;
virtual int GetExpectedTextWidth(int length) const OVERRIDE;
virtual int GetStyle() const OVERRIDE;
virtual std::string GetFontName() const OVERRIDE;
@@ -104,6 +102,7 @@ class GFX_EXPORT PlatformFontPango : public PlatformFont {
// Cached metrics, generated at construction.
int height_pixels_;
int ascent_pixels_;
+ int cap_height_pixels_;
// The pango metrics are much more expensive so we wait until we need them
// to compute them.
diff --git a/chromium/ui/gfx/platform_font_win.cc b/chromium/ui/gfx/platform_font_win.cc
index 0209be6673e..4acaf64b34a 100644
--- a/chromium/ui/gfx/platform_font_win.cc
+++ b/chromium/ui/gfx/platform_font_win.cc
@@ -101,7 +101,7 @@ Font PlatformFontWin::DeriveFontWithHeight(int height, int style) {
int font_height = font.GetHeight();
int font_size = font.GetFontSize();
while (font_height > height && font_size != min_font_size) {
- font = font.DeriveFont(-1, style);
+ font = font.Derive(-1, style);
if (font_height == font.GetHeight() && font_size == font.GetFontSize())
break;
font_height = font.GetHeight();
@@ -145,18 +145,9 @@ int PlatformFontWin::GetCapHeight() const {
return font_ref_->cap_height();
}
-int PlatformFontWin::GetAverageCharacterWidth() const {
- return font_ref_->ave_char_width();
-}
-
-int PlatformFontWin::GetStringWidth(const base::string16& text) const {
- return Canvas::GetStringWidth(text,
- Font(const_cast<PlatformFontWin*>(this)));
-}
-
int PlatformFontWin::GetExpectedTextWidth(int length) const {
return length * std::min(font_ref_->GetDluBaseX(),
- GetAverageCharacterWidth());
+ font_ref_->ave_char_width());
}
int PlatformFontWin::GetStyle() const {
@@ -211,7 +202,7 @@ void PlatformFontWin::InitWithCopyOfHFONT(HFONT hfont) {
void PlatformFontWin::InitWithFontNameAndSize(const std::string& font_name,
int font_size) {
HFONT hf = ::CreateFont(-font_size, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- UTF8ToUTF16(font_name).c_str());
+ base::UTF8ToUTF16(font_name).c_str());
font_ref_ = CreateHFontRef(hf);
}
@@ -289,7 +280,7 @@ PlatformFontWin::HFontRef::HFontRef(HFONT hfont,
LOGFONT font_info;
GetObject(hfont_, sizeof(LOGFONT), &font_info);
- font_name_ = UTF16ToUTF8(base::string16(font_info.lfFaceName));
+ font_name_ = base::UTF16ToUTF8(base::string16(font_info.lfFaceName));
if (font_info.lfHeight < 0)
requested_font_size_ = -font_info.lfHeight;
}
diff --git a/chromium/ui/gfx/platform_font_win.h b/chromium/ui/gfx/platform_font_win.h
index 4826f777ffc..2c6f51e0508 100644
--- a/chromium/ui/gfx/platform_font_win.h
+++ b/chromium/ui/gfx/platform_font_win.h
@@ -58,8 +58,6 @@ class GFX_EXPORT PlatformFontWin : public PlatformFont {
virtual int GetHeight() const OVERRIDE;
virtual int GetBaseline() const OVERRIDE;
virtual int GetCapHeight() const OVERRIDE;
- virtual int GetAverageCharacterWidth() const OVERRIDE;
- virtual int GetStringWidth(const base::string16& text) const OVERRIDE;
virtual int GetExpectedTextWidth(int length) const OVERRIDE;
virtual int GetStyle() const OVERRIDE;
virtual std::string GetFontName() const OVERRIDE;
diff --git a/chromium/ui/gfx/platform_font_win_unittest.cc b/chromium/ui/gfx/platform_font_win_unittest.cc
index bfbe92203d1..1ecdde1d352 100644
--- a/chromium/ui/gfx/platform_font_win_unittest.cc
+++ b/chromium/ui/gfx/platform_font_win_unittest.cc
@@ -20,15 +20,15 @@ gfx::Font AdjustFontSizeForHeight(const gfx::Font& base_font,
Font expected_font = base_font;
if (base_font.GetHeight() < target_height) {
// Increase size while height is <= |target_height|.
- Font larger_font = base_font.DeriveFont(1, 0);
+ Font larger_font = base_font.Derive(1, 0);
while (larger_font.GetHeight() <= target_height) {
expected_font = larger_font;
- larger_font = larger_font.DeriveFont(1, 0);
+ larger_font = larger_font.Derive(1, 0);
}
} else if (expected_font.GetHeight() > target_height) {
// Decrease size until height is <= |target_height|.
do {
- expected_font = expected_font.DeriveFont(-1, 0);
+ expected_font = expected_font.Derive(-1, 0);
} while (expected_font.GetHeight() > target_height);
}
return expected_font;
@@ -60,7 +60,7 @@ TEST(PlatformFontWinTest, DeriveFontWithHeight) {
EXPECT_EQ(Font::BOLD, derived_font.GetStyle());
// Test that deriving from the new font has the expected result.
- Font rederived_font = derived_font.DeriveFont(1, 0);
+ Font rederived_font = derived_font.Derive(1, 0);
expected_font = Font(derived_font.GetFontName(),
derived_font.GetFontSize() + 1);
EXPECT_EQ(expected_font.GetFontName(), rederived_font.GetFontName());
diff --git a/chromium/ui/gfx/point.h b/chromium/ui/gfx/point.h
index 020c4e1251a..bbca081095d 100644
--- a/chromium/ui/gfx/point.h
+++ b/chromium/ui/gfx/point.h
@@ -1,90 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_POINT_H_
-#define UI_GFX_POINT_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/point.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/point_base.h"
-#include "ui/gfx/point_f.h"
-#include "ui/gfx/vector2d.h"
-
-#if defined(OS_WIN)
-typedef unsigned long DWORD;
-typedef struct tagPOINT POINT;
-#elif defined(OS_IOS)
-#include <CoreGraphics/CoreGraphics.h>
-#elif defined(OS_MACOSX)
-#include <ApplicationServices/ApplicationServices.h>
-#endif
-
-namespace gfx {
-
-// A point has an x and y coordinate.
-class GFX_EXPORT Point : public PointBase<Point, int, Vector2d> {
- public:
- Point() : PointBase<Point, int, Vector2d>(0, 0) {}
- Point(int x, int y) : PointBase<Point, int, Vector2d>(x, y) {}
-#if defined(OS_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 defined(OS_MACOSX)
- explicit Point(const CGPoint& point);
-#endif
-
- ~Point() {}
-
-#if defined(OS_WIN)
- POINT ToPOINT() const;
-#elif defined(OS_MACOSX)
- CGPoint ToCGPoint() const;
-#endif
-
- operator PointF() const {
- return PointF(x(), y());
- }
-
- // Returns a string representation of point.
- std::string ToString() const;
-};
-
-inline bool operator==(const Point& lhs, const Point& rhs) {
- return lhs.x() == rhs.x() && lhs.y() == rhs.y();
-}
-
-inline bool operator!=(const Point& lhs, const Point& rhs) {
- return !(lhs == rhs);
-}
-
-inline Point operator+(const Point& lhs, const Vector2d& rhs) {
- Point result(lhs);
- result += rhs;
- return result;
-}
-
-inline Point operator-(const Point& lhs, const Vector2d& rhs) {
- Point result(lhs);
- result -= rhs;
- return result;
-}
-
-inline Vector2d operator-(const Point& lhs, const Point& rhs) {
- return Vector2d(lhs.x() - rhs.x(), lhs.y() - rhs.y());
-}
-
-inline Point PointAtOffsetFromOrigin(const Vector2d& offset_from_origin) {
- return Point(offset_from_origin.x(), offset_from_origin.y());
-}
-
-#if !defined(COMPILER_MSVC)
-extern template class PointBase<Point, int, Vector2d>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_POINT_H_
diff --git a/chromium/ui/gfx/point3_f.h b/chromium/ui/gfx/point3_f.h
index 485f6558136..8c57c578f48 100644
--- a/chromium/ui/gfx/point3_f.h
+++ b/chromium/ui/gfx/point3_f.h
@@ -1,120 +1,7 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// 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_POINT3_F_H_
-#define UI_GFX_POINT3_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/point3_f.h"
-#include <string>
-
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/point_f.h"
-#include "ui/gfx/vector3d_f.h"
-
-namespace gfx {
-
-// A point has an x, y and z coordinate.
-class GFX_EXPORT Point3F {
- public:
- Point3F() : x_(0), y_(0), z_(0) {}
-
- Point3F(float x, float y, float z) : x_(x), y_(y), z_(z) {}
-
- 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 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_; }
-
- void set_x(float x) { x_ = x; }
- void set_y(float y) { y_ = y; }
- void set_z(float z) { z_ = z; }
-
- void SetPoint(float x, float y, float z) {
- x_ = x;
- y_ = y;
- z_ = z;
- }
-
- // 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_;
- float dy = y_ - other.y_;
- float dz = z_ - other.z_;
- return dx * dx + dy * dy + dz * dz;
- }
-
- PointF AsPointF() const { return PointF(x_, y_); }
-
- // Returns a string representation of 3d point.
- std::string ToString() const;
-
- private:
- float x_;
- float y_;
- float z_;
-
- // copy/assign are allowed.
-};
-
-inline bool operator==(const Point3F& lhs, const Point3F& rhs) {
- return lhs.x() == rhs.x() && lhs.y() == rhs.y() && lhs.z() == rhs.z();
-}
-
-inline bool operator!=(const Point3F& lhs, const Point3F& rhs) {
- return !(lhs == rhs);
-}
-
-// Add a vector to a point, producing a new point offset by the vector.
-GFX_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.
-GFX_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.
-GFX_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, float scale) {
- return ScalePoint(p, scale, scale, scale);
-}
-
-} // namespace gfx
-
-#endif // UI_GFX_POINT3_F_H_
diff --git a/chromium/ui/gfx/point_conversions.h b/chromium/ui/gfx/point_conversions.h
index 942edd711cc..b7c961fe923 100644
--- a/chromium/ui/gfx/point_conversions.h
+++ b/chromium/ui/gfx/point_conversions.h
@@ -1,24 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_POINT_CONVERSIONS_H_
-#define UI_GFX_POINT_CONVERSIONS_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/point_conversions.h"
-#include "ui/gfx/point.h"
-#include "ui/gfx/point_f.h"
-
-namespace gfx {
-
-// Returns a Point with each component from the input PointF floored.
-GFX_EXPORT Point ToFlooredPoint(const PointF& point);
-
-// Returns a Point with each component from the input PointF ceiled.
-GFX_EXPORT Point ToCeiledPoint(const PointF& point);
-
-// Returns a Point with each component from the input PointF rounded.
-GFX_EXPORT Point ToRoundedPoint(const PointF& point);
-
-} // namespace gfx
-
-#endif // UI_GFX_POINT_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/point_f.h b/chromium/ui/gfx/point_f.h
index 664c18d8aa0..f4be8ff0578 100644
--- a/chromium/ui/gfx/point_f.h
+++ b/chromium/ui/gfx/point_f.h
@@ -1,75 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_POINT_F_H_
-#define UI_GFX_POINT_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/point_f.h"
-#include <string>
-
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/point_base.h"
-#include "ui/gfx/vector2d_f.h"
-
-namespace gfx {
-
-// A floating version of gfx::Point.
-class GFX_EXPORT PointF : public PointBase<PointF, float, Vector2dF> {
- public:
- PointF() : PointBase<PointF, float, Vector2dF>(0, 0) {}
- PointF(float x, float y) : PointBase<PointF, float, Vector2dF>(x, y) {}
- ~PointF() {}
-
- void Scale(float scale) {
- Scale(scale, scale);
- }
-
- void Scale(float x_scale, float y_scale) {
- SetPoint(x() * x_scale, y() * y_scale);
- }
-
- // Returns a string representation of point.
- std::string ToString() const;
-};
-
-inline 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) {
- return !(lhs == rhs);
-}
-
-inline PointF operator+(const PointF& lhs, const Vector2dF& rhs) {
- PointF result(lhs);
- result += rhs;
- return result;
-}
-
-inline PointF operator-(const PointF& lhs, const Vector2dF& rhs) {
- PointF result(lhs);
- result -= rhs;
- return result;
-}
-
-inline Vector2dF operator-(const PointF& lhs, const PointF& rhs) {
- return Vector2dF(lhs.x() - rhs.x(), lhs.y() - rhs.y());
-}
-
-inline PointF PointAtOffsetFromOrigin(const Vector2dF& offset_from_origin) {
- return PointF(offset_from_origin.x(), offset_from_origin.y());
-}
-
-GFX_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);
-}
-
-#if !defined(COMPILER_MSVC)
-extern template class PointBase<PointF, float, Vector2dF>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_POINT_F_H_
diff --git a/chromium/ui/gfx/quad_f.h b/chromium/ui/gfx/quad_f.h
index b8a42e9883e..05bf9d82dfc 100644
--- a/chromium/ui/gfx/quad_f.h
+++ b/chromium/ui/gfx/quad_f.h
@@ -1,109 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_QUAD_F_H_
-#define UI_GFX_QUAD_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/quad_f.h"
-#include <algorithm>
-#include <cmath>
-#include <string>
-
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/point_f.h"
-#include "ui/gfx/rect_f.h"
-
-namespace gfx {
-
-// A Quad is defined by four corners, allowing it to have edges that are not
-// axis-aligned, unlike a Rect.
-class GFX_EXPORT QuadF {
- public:
- QuadF() {}
- QuadF(const PointF& p1, const PointF& p2, const PointF& p3, const PointF& p4)
- : p1_(p1),
- p2_(p2),
- p3_(p3),
- p4_(p4) {}
-
- explicit QuadF(const RectF& rect)
- : p1_(rect.x(), rect.y()),
- p2_(rect.right(), rect.y()),
- p3_(rect.right(), rect.bottom()),
- p4_(rect.x(), rect.bottom()) {}
-
- void operator=(const RectF& rect);
-
- void set_p1(const PointF& p) { p1_ = p; }
- void set_p2(const PointF& p) { p2_ = p; }
- void set_p3(const PointF& p) { p3_ = p; }
- void set_p4(const PointF& p) { p4_ = p; }
-
- const PointF& p1() const { return p1_; }
- const PointF& p2() const { return p2_; }
- const PointF& p3() const { return p3_; }
- const PointF& p4() const { return p4_; }
-
- // Returns true if the quad is an axis-aligned rectangle.
- bool IsRectilinear() const;
-
- // Returns true if the points of the quad are in counter-clockwise order. This
- // assumes that the quad is convex, and that no three points are collinear.
- bool IsCounterClockwise() const;
-
- // Returns true if the |point| is contained within the quad, or lies on on
- // edge of the quad.
- bool Contains(const gfx::PointF& point) 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,
- // rather than being strictly inside it.
- RectF BoundingBox() const {
- float rl = std::min(std::min(p1_.x(), p2_.x()), std::min(p3_.x(), p4_.x()));
- float rr = std::max(std::max(p1_.x(), p2_.x()), std::max(p3_.x(), p4_.x()));
- float rt = std::min(std::min(p1_.y(), p2_.y()), std::min(p3_.y(), p4_.y()));
- float rb = std::max(std::max(p1_.y(), p2_.y()), std::max(p3_.y(), p4_.y()));
- return RectF(rl, rt, rr - rl, rb - rt);
- }
-
- // Add a vector to the quad, offseting each point in the quad by the vector.
- void operator+=(const Vector2dF& rhs);
- // Subtract a vector from the quad, offseting each point in the quad by the
- // inverse of the vector.
- void operator-=(const Vector2dF& rhs);
-
- // Scale each point in the quad by the |scale| factor.
- void Scale(float scale) { Scale(scale, scale); }
-
- // Scale each point in the quad by the scale factors along each axis.
- void Scale(float x_scale, float y_scale);
-
- // Returns a string representation of quad.
- std::string ToString() const;
-
- private:
- PointF p1_;
- PointF p2_;
- PointF p3_;
- PointF p4_;
-};
-
-inline bool operator==(const QuadF& lhs, const QuadF& rhs) {
- return
- lhs.p1() == rhs.p1() && lhs.p2() == rhs.p2() &&
- lhs.p3() == rhs.p3() && lhs.p4() == rhs.p4();
-}
-
-inline bool operator!=(const QuadF& lhs, const QuadF& rhs) {
- return !(lhs == rhs);
-}
-
-// Add a vector to a quad, offseting each point in the quad by the vector.
-GFX_EXPORT QuadF operator+(const QuadF& lhs, const Vector2dF& rhs);
-// Subtract a vector from a quad, offseting each point in the quad by the
-// inverse of the vector.
-GFX_EXPORT QuadF operator-(const QuadF& lhs, const Vector2dF& rhs);
-
-} // namespace gfx
-
-#endif // UI_GFX_QUAD_F_H_
diff --git a/chromium/ui/gfx/rect.h b/chromium/ui/gfx/rect.h
index df7f9aac366..a83d6b42cef 100644
--- a/chromium/ui/gfx/rect.h
+++ b/chromium/ui/gfx/rect.h
@@ -1,145 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
-// Defines a simple integer 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.
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/rect.h"
-#ifndef UI_GFX_RECT_H_
-#define UI_GFX_RECT_H_
-
-#include <cmath>
-#include <string>
-
-#include "ui/gfx/point.h"
-#include "ui/gfx/rect_base.h"
-#include "ui/gfx/rect_f.h"
-#include "ui/gfx/size.h"
-#include "ui/gfx/vector2d.h"
-
-#if defined(OS_WIN)
-typedef struct tagRECT RECT;
-#elif defined(TOOLKIT_GTK)
-typedef struct _GdkRectangle GdkRectangle;
-#elif defined(OS_IOS)
-#include <CoreGraphics/CoreGraphics.h>
-#elif defined(OS_MACOSX)
-#include <ApplicationServices/ApplicationServices.h>
-#endif
-
-namespace gfx {
-
-class Insets;
-
-class GFX_EXPORT Rect
- : public RectBase<Rect, Point, Size, Insets, Vector2d, int> {
- public:
- Rect() : RectBase<Rect, Point, Size, Insets, Vector2d, int>(Point()) {}
-
- Rect(int width, int height)
- : RectBase<Rect, Point, Size, Insets, Vector2d, int>
- (Size(width, height)) {}
-
- Rect(int x, int y, int width, int height)
- : RectBase<Rect, Point, Size, Insets, Vector2d, int>
- (Point(x, y), Size(width, height)) {}
-
-#if defined(OS_WIN)
- explicit Rect(const RECT& r);
-#elif defined(OS_MACOSX)
- explicit Rect(const CGRect& r);
-#elif defined(TOOLKIT_GTK)
- explicit Rect(const GdkRectangle& r);
-#endif
-
- explicit Rect(const gfx::Size& size)
- : RectBase<Rect, Point, Size, Insets, Vector2d, int>(size) {}
-
- Rect(const gfx::Point& origin, const gfx::Size& size)
- : RectBase<Rect, Point, Size, Insets, Vector2d, int>(origin, size) {}
-
- ~Rect() {}
-
-#if defined(OS_WIN)
- // Construct an equivalent Win32 RECT object.
- RECT ToRECT() const;
-#elif defined(TOOLKIT_GTK)
- GdkRectangle ToGdkRectangle() const;
-#elif defined(OS_MACOSX)
- // Construct an equivalent CoreGraphics object.
- CGRect ToCGRect() const;
-#endif
-
- operator RectF() const {
- return RectF(origin().x(), origin().y(), size().width(), size().height());
- }
-
- std::string ToString() const;
-};
-
-inline bool operator==(const Rect& lhs, const Rect& rhs) {
- return lhs.origin() == rhs.origin() && lhs.size() == rhs.size();
-}
-
-inline bool operator!=(const Rect& lhs, const Rect& rhs) {
- return !(lhs == rhs);
-}
-
-GFX_EXPORT Rect operator+(const Rect& lhs, const Vector2d& rhs);
-GFX_EXPORT Rect operator-(const Rect& lhs, const Vector2d& rhs);
-
-inline Rect operator+(const Vector2d& lhs, const Rect& rhs) {
- return rhs + lhs;
-}
-
-GFX_EXPORT Rect IntersectRects(const Rect& a, const Rect& b);
-GFX_EXPORT Rect UnionRects(const Rect& a, const Rect& b);
-GFX_EXPORT Rect SubtractRects(const Rect& a, const Rect& b);
-
-// Constructs a rectangle with |p1| and |p2| as opposite corners.
-//
-// This could also be thought of as "the smallest rect that contains both
-// 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.
-GFX_EXPORT Rect BoundingRect(const Point& p1, const Point& p2);
-
-inline Rect ScaleToEnclosingRect(const Rect& rect,
- float x_scale,
- float y_scale) {
- int x = std::floor(rect.x() * x_scale);
- int y = std::floor(rect.y() * y_scale);
- int r = rect.width() == 0 ? x : std::ceil(rect.right() * x_scale);
- int b = rect.height() == 0 ? y : std::ceil(rect.bottom() * y_scale);
- return Rect(x, y, r - x, b - y);
-}
-
-inline Rect ScaleToEnclosingRect(const Rect& rect, float scale) {
- return ScaleToEnclosingRect(rect, scale, scale);
-}
-
-inline Rect ScaleToEnclosedRect(const Rect& rect,
- float x_scale,
- float y_scale) {
- int x = std::ceil(rect.x() * x_scale);
- int y = std::ceil(rect.y() * y_scale);
- int r = rect.width() == 0 ? x : std::floor(rect.right() * x_scale);
- int b = rect.height() == 0 ? y : std::floor(rect.bottom() * y_scale);
- return Rect(x, y, r - x, b - y);
-}
-
-inline Rect ScaleToEnclosedRect(const Rect& rect, float scale) {
- return ScaleToEnclosedRect(rect, scale, scale);
-}
-
-#if !defined(COMPILER_MSVC)
-extern template class RectBase<Rect, Point, Size, Insets, Vector2d, int>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_RECT_H_
diff --git a/chromium/ui/gfx/rect_conversions.h b/chromium/ui/gfx/rect_conversions.h
index 988f6c76418..537435120c0 100644
--- a/chromium/ui/gfx/rect_conversions.h
+++ b/chromium/ui/gfx/rect_conversions.h
@@ -1,36 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_RECT_CONVERSIONS_H_
-#define UI_GFX_RECT_CONVERSIONS_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/rect_conversions.h"
-#include "ui/gfx/rect.h"
-#include "ui/gfx/rect_f.h"
-
-namespace gfx {
-
-// Returns the smallest Rect that encloses the given RectF.
-GFX_EXPORT Rect ToEnclosingRect(const RectF& rect);
-
-// Returns the largest Rect that is enclosed by the given RectF.
-GFX_EXPORT Rect ToEnclosedRect(const RectF& rect);
-
-// Returns the Rect after snapping the corners of the RectF to an integer grid.
-// This should only be used when the RectF you provide is expected to be an
-// integer rect with floating point error. If it is an arbitrary RectF, then
-// you should use a different method.
-GFX_EXPORT Rect ToNearestRect(const RectF& rect);
-
-// Returns true if the Rect produced after snapping the corners of the RectF
-// to an integer grid is withing |distance|.
-GFX_EXPORT bool IsNearestRectWithinDistance(
- const gfx::RectF& rect, float distance);
-
-// Returns a Rect obtained by flooring the values of the given RectF.
-// Please prefer the previous two functions in new code.
-GFX_EXPORT Rect ToFlooredRectDeprecated(const RectF& rect);
-
-} // namespace gfx
-
-#endif // UI_GFX_RECT_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/rect_f.h b/chromium/ui/gfx/rect_f.h
index 09de529a627..71564bb65c8 100644
--- a/chromium/ui/gfx/rect_f.h
+++ b/chromium/ui/gfx/rect_f.h
@@ -1,113 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_RECT_F_H_
-#define UI_GFX_RECT_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/rect_f.h"
-#include <string>
-
-#include "ui/gfx/point_f.h"
-#include "ui/gfx/rect_base.h"
-#include "ui/gfx/size_f.h"
-#include "ui/gfx/vector2d_f.h"
-
-namespace gfx {
-
-class InsetsF;
-
-// A floating version of gfx::Rect.
-class GFX_EXPORT RectF
- : public RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float> {
- public:
- RectF()
- : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
- (SizeF()) {}
-
- RectF(float width, float height)
- : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
- (SizeF(width, height)) {}
-
- RectF(float x, float y, float width, float height)
- : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
- (PointF(x, y), SizeF(width, height)) {}
-
- explicit RectF(const SizeF& size)
- : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
- (size) {}
-
- RectF(const PointF& origin, const SizeF& size)
- : RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>
- (origin, size) {}
-
- ~RectF() {}
-
- // Scales the rectangle by |scale|.
- void Scale(float scale) {
- Scale(scale, scale);
- }
-
- void Scale(float x_scale, float y_scale) {
- set_origin(ScalePoint(origin(), x_scale, y_scale));
- set_size(ScaleSize(size(), 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
- // clamping.
- bool IsExpressibleAsRect() const;
-
- std::string ToString() const;
-};
-
-inline 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) {
- return !(lhs == rhs);
-}
-
-inline RectF operator+(const RectF& lhs, const Vector2dF& rhs) {
- return RectF(lhs.x() + rhs.x(), lhs.y() + rhs.y(),
- lhs.width(), lhs.height());
-}
-
-inline RectF operator-(const RectF& lhs, const Vector2dF& rhs) {
- return RectF(lhs.x() - rhs.x(), lhs.y() - rhs.y(),
- lhs.width(), lhs.height());
-}
-
-inline RectF operator+(const Vector2dF& lhs, const RectF& rhs) {
- return rhs + lhs;
-}
-
-GFX_EXPORT RectF IntersectRects(const RectF& a, const RectF& b);
-GFX_EXPORT RectF UnionRects(const RectF& a, const RectF& b);
-GFX_EXPORT RectF SubtractRects(const RectF& a, const RectF& b);
-
-inline RectF ScaleRect(const RectF& r, float x_scale, float y_scale) {
- return RectF(r.x() * x_scale, r.y() * y_scale,
- r.width() * x_scale, r.height() * y_scale);
-}
-
-inline RectF ScaleRect(const RectF& r, float scale) {
- return ScaleRect(r, scale, scale);
-}
-
-// Constructs a rectangle with |p1| and |p2| as opposite corners.
-//
-// This could also be thought of as "the smallest rect that contains both
-// 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.
-GFX_EXPORT RectF BoundingRect(const PointF& p1, const PointF& p2);
-
-#if !defined(COMPILER_MSVC)
-extern template class RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_RECT_F_H_
diff --git a/chromium/ui/gfx/render_text.cc b/chromium/ui/gfx/render_text.cc
index e8e3436f11c..c7871ee7a05 100644
--- a/chromium/ui/gfx/render_text.cc
+++ b/chromium/ui/gfx/render_text.cc
@@ -7,18 +7,24 @@
#include <algorithm>
#include <climits>
+#include "base/command_line.h"
#include "base/i18n/break_iterator.h"
#include "base/logging.h"
#include "base/stl_util.h"
+#include "base/strings/utf_string_conversions.h"
#include "third_party/icu/source/common/unicode/rbbi.h"
#include "third_party/icu/source/common/unicode/utf16.h"
#include "third_party/skia/include/core/SkTypeface.h"
#include "third_party/skia/include/effects/SkGradientShader.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/insets.h"
+#include "ui/gfx/render_text_harfbuzz.h"
+#include "ui/gfx/scoped_canvas.h"
#include "ui/gfx/skia_util.h"
+#include "ui/gfx/switches.h"
#include "ui/gfx/text_constants.h"
#include "ui/gfx/text_elider.h"
+#include "ui/gfx/text_utils.h"
#include "ui/gfx/utf16_indexing.h"
namespace gfx {
@@ -72,20 +78,20 @@ int DetermineBaselineCenteringText(const Rect& display_rect,
return baseline + std::max(min_shift, std::min(max_shift, baseline_shift));
}
-// Converts |gfx::Font::FontStyle| flags to |SkTypeface::Style| flags.
+// Converts |Font::FontStyle| flags to |SkTypeface::Style| flags.
SkTypeface::Style ConvertFontStyleToSkiaTypefaceStyle(int font_style) {
int skia_style = SkTypeface::kNormal;
- skia_style |= (font_style & gfx::Font::BOLD) ? SkTypeface::kBold : 0;
- skia_style |= (font_style & gfx::Font::ITALIC) ? SkTypeface::kItalic : 0;
+ skia_style |= (font_style & Font::BOLD) ? SkTypeface::kBold : 0;
+ skia_style |= (font_style & Font::ITALIC) ? SkTypeface::kItalic : 0;
return static_cast<SkTypeface::Style>(skia_style);
}
// Given |font| and |display_width|, returns the width of the fade gradient.
-int CalculateFadeGradientWidth(const Font& font, int display_width) {
+int CalculateFadeGradientWidth(const FontList& font_list, int display_width) {
// Fade in/out about 2.5 characters of the beginning/end of the string.
// The .5 here is helpful if one of the characters is a space.
// Use a quarter of the display width if the display width is very short.
- const int average_character_width = font.GetAverageCharacterWidth();
+ const int average_character_width = font_list.GetExpectedTextWidth(1);
const double gradient_width = std::min(average_character_width * 2.5,
display_width / 4.0);
DCHECK_GE(gradient_width, 0.0);
@@ -158,7 +164,8 @@ namespace internal {
const SkScalar kUnderlineMetricsNotSet = -1.0f;
SkiaTextRenderer::SkiaTextRenderer(Canvas* canvas)
- : canvas_skia_(canvas->sk_canvas()),
+ : canvas_(canvas),
+ canvas_skia_(canvas->sk_canvas()),
started_drawing_(false),
underline_thickness_(kUnderlineMetricsNotSet),
underline_position_(0.0f) {
@@ -168,6 +175,7 @@ SkiaTextRenderer::SkiaTextRenderer(Canvas* canvas)
paint_.setAntiAlias(true);
paint_.setSubpixelText(true);
paint_.setLCDRenderText(true);
+ paint_.setHinting(SkPaint::kNormal_Hinting);
bounds_.setEmpty();
}
@@ -190,11 +198,16 @@ void SkiaTextRenderer::SetDrawLooper(SkDrawLooper* draw_looper) {
paint_.setLooper(draw_looper);
}
-void SkiaTextRenderer::SetFontSmoothingSettings(bool enable_smoothing,
- bool enable_lcd_text) {
- paint_.setAntiAlias(enable_smoothing);
- paint_.setSubpixelText(enable_smoothing);
- paint_.setLCDRenderText(enable_lcd_text);
+void SkiaTextRenderer::SetFontSmoothingSettings(bool antialiasing,
+ bool subpixel_rendering,
+ bool subpixel_positioning) {
+ paint_.setAntiAlias(antialiasing);
+ paint_.setLCDRenderText(subpixel_rendering);
+ paint_.setSubpixelText(subpixel_positioning);
+}
+
+void SkiaTextRenderer::SetFontHinting(SkPaint::Hinting hinting) {
+ paint_.setHinting(hinting);
}
void SkiaTextRenderer::SetTypeface(SkTypeface* typeface) {
@@ -209,17 +222,14 @@ void SkiaTextRenderer::SetFontFamilyWithStyle(const std::string& family,
int style) {
DCHECK(!family.empty());
- SkTypeface::Style skia_style = ConvertFontStyleToSkiaTypefaceStyle(style);
- skia::RefPtr<SkTypeface> typeface =
- skia::AdoptRef(SkTypeface::CreateFromName(family.c_str(), skia_style));
+ skia::RefPtr<SkTypeface> typeface = CreateSkiaTypeface(family.c_str(), style);
if (typeface) {
// |paint_| adds its own ref. So don't |release()| it from the ref ptr here.
SetTypeface(typeface.get());
// Enable fake bold text if bold style is needed but new typeface does not
// have it.
- paint_.setFakeBoldText((skia_style & SkTypeface::kBold) &&
- !typeface->isBold());
+ paint_.setFakeBoldText((style & Font::BOLD) && !typeface->isBold());
}
}
@@ -271,8 +281,20 @@ void SkiaTextRenderer::DrawDecorations(int x, int y, int width, bool underline,
DrawUnderline(x, y, width);
if (strike)
DrawStrike(x, y, width);
- if (diagonal_strike)
- DrawDiagonalStrike(x, y, width);
+ if (diagonal_strike) {
+ if (!diagonal_)
+ diagonal_.reset(new DiagonalStrike(canvas_, Point(x, y), paint_));
+ diagonal_->AddPiece(width, paint_.getColor());
+ } else if (diagonal_) {
+ EndDiagonalStrike();
+ }
+}
+
+void SkiaTextRenderer::EndDiagonalStrike() {
+ if (diagonal_) {
+ diagonal_->Draw();
+ diagonal_.reset();
+ }
}
void SkiaTextRenderer::DrawUnderline(int x, int y, int width) {
@@ -294,15 +316,56 @@ void SkiaTextRenderer::DrawStrike(int x, int y, int width) const {
canvas_skia_->drawRect(r, paint_);
}
-void SkiaTextRenderer::DrawDiagonalStrike(int x, int y, int width) const {
+SkiaTextRenderer::DiagonalStrike::DiagonalStrike(Canvas* canvas,
+ Point start,
+ const SkPaint& paint)
+ : canvas_(canvas),
+ matrix_(canvas->sk_canvas()->getTotalMatrix()),
+ start_(start),
+ paint_(paint),
+ total_length_(0) {
+}
+
+SkiaTextRenderer::DiagonalStrike::~DiagonalStrike() {
+}
+
+void SkiaTextRenderer::DiagonalStrike::AddPiece(int length, SkColor color) {
+ pieces_.push_back(Piece(length, color));
+ total_length_ += length;
+}
+
+void SkiaTextRenderer::DiagonalStrike::Draw() {
const SkScalar text_size = paint_.getTextSize();
const SkScalar offset = SkScalarMul(text_size, kDiagonalStrikeMarginOffset);
+ const int thickness =
+ SkScalarCeilToInt(SkScalarMul(text_size, kLineThickness) * 2);
+ const int height = SkScalarCeilToInt(text_size - offset);
+ const Point end = start_ + Vector2d(total_length_, -height);
+ const int clip_height = height + 2 * thickness;
+
+ paint_.setAntiAlias(true);
+ paint_.setStrokeWidth(thickness);
+
+ ScopedCanvas scoped_canvas(canvas_);
+
+ SkCanvas* sk_canvas = canvas_->sk_canvas();
+ sk_canvas->setMatrix(matrix_);
+
+ const bool clipped = pieces_.size() > 1;
+ int x = start_.x();
+ for (size_t i = 0; i < pieces_.size(); ++i) {
+ paint_.setColor(pieces_[i].second);
+
+ if (clipped) {
+ sk_canvas->clipRect(RectToSkRect(
+ Rect(x, end.y() - thickness, pieces_[i].first, clip_height)),
+ SkRegion::kReplace_Op);
+ }
+
+ canvas_->DrawLine(start_, end, paint_);
- SkPaint paint(paint_);
- paint.setAntiAlias(true);
- paint.setStyle(SkPaint::kFill_Style);
- paint.setStrokeWidth(SkScalarMul(text_size, kLineThickness) * 2);
- canvas_skia_->drawLine(x, y, x + width, y - text_size + offset, paint);
+ x += pieces_[i].first;
+ }
}
StyleIterator::StyleIterator(const BreakList<SkColor>& colors,
@@ -337,11 +400,30 @@ Line::Line() : preceding_heights(0), baseline(0) {}
Line::~Line() {}
+skia::RefPtr<SkTypeface> CreateSkiaTypeface(const std::string& family,
+ int style) {
+ SkTypeface::Style skia_style = ConvertFontStyleToSkiaTypefaceStyle(style);
+ return skia::AdoptRef(SkTypeface::CreateFromName(family.c_str(), skia_style));
+}
+
} // namespace internal
RenderText::~RenderText() {
}
+RenderText* RenderText::CreateInstance() {
+#if defined(OS_MACOSX) && defined(TOOLKIT_VIEWS)
+ // Use the more complete HarfBuzz implementation for Views controls on Mac.
+ return new RenderTextHarfBuzz;
+#else
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableHarfBuzzRenderText)) {
+ return new RenderTextHarfBuzz;
+ }
+ return CreateNativeInstance();
+#endif
+}
+
void RenderText::SetText(const base::string16& text) {
DCHECK(!composition_range_.IsValid());
if (text_ == text)
@@ -365,7 +447,6 @@ void RenderText::SetText(const base::string16& text) {
obscured_reveal_index_ = -1;
UpdateLayoutText();
- ResetLayout();
}
void RenderText::SetHorizontalAlignment(HorizontalAlignment alignment) {
@@ -383,18 +464,6 @@ void RenderText::SetFontList(const FontList& font_list) {
ResetLayout();
}
-void RenderText::SetFont(const Font& font) {
- SetFontList(FontList(font));
-}
-
-void RenderText::SetFontSize(int size) {
- SetFontList(font_list_.DeriveFontListWithSize(size));
-}
-
-const Font& RenderText::GetPrimaryFont() const {
- return font_list_.GetPrimaryFont();
-}
-
void RenderText::SetCursorEnabled(bool cursor_enabled) {
cursor_enabled_ = cursor_enabled;
cached_bounds_and_offset_valid_ = false;
@@ -411,7 +480,6 @@ void RenderText::SetObscured(bool obscured) {
obscured_reveal_index_ = -1;
cached_bounds_and_offset_valid_ = false;
UpdateLayoutText();
- ResetLayout();
}
}
@@ -422,7 +490,6 @@ void RenderText::SetObscuredRevealIndex(int index) {
obscured_reveal_index_ = index;
cached_bounds_and_offset_valid_ = false;
UpdateLayoutText();
- ResetLayout();
}
void RenderText::SetMultiline(bool multiline) {
@@ -433,11 +500,23 @@ void RenderText::SetMultiline(bool multiline) {
}
}
+void RenderText::SetElideBehavior(ElideBehavior elide_behavior) {
+ // TODO(skanuj) : Add a test for triggering layout change.
+ if (elide_behavior_ != elide_behavior) {
+ elide_behavior_ = elide_behavior;
+ UpdateLayoutText();
+ }
+}
+
void RenderText::SetDisplayRect(const Rect& r) {
- display_rect_ = r;
- baseline_ = kInvalidBaseline;
- cached_bounds_and_offset_valid_ = false;
- lines_.clear();
+ if (r != display_rect_) {
+ display_rect_ = r;
+ baseline_ = kInvalidBaseline;
+ cached_bounds_and_offset_valid_ = false;
+ lines_.clear();
+ if (elide_behavior_ != TRUNCATE)
+ UpdateLayoutText();
+ }
}
void RenderText::SetCursorPosition(size_t position) {
@@ -447,26 +526,28 @@ void RenderText::SetCursorPosition(size_t position) {
void RenderText::MoveCursor(BreakType break_type,
VisualCursorDirection direction,
bool select) {
- SelectionModel position(cursor_position(), selection_model_.caret_affinity());
+ SelectionModel cursor(cursor_position(), selection_model_.caret_affinity());
// Cancelling a selection moves to the edge of the selection.
if (break_type != LINE_BREAK && !selection().is_empty() && !select) {
SelectionModel selection_start = GetSelectionModelForSelectionStart();
int start_x = GetCursorBounds(selection_start, true).x();
- int cursor_x = GetCursorBounds(position, true).x();
+ int cursor_x = GetCursorBounds(cursor, true).x();
// Use the selection start if it is left (when |direction| is CURSOR_LEFT)
// or right (when |direction| is CURSOR_RIGHT) of the selection end.
if (direction == CURSOR_RIGHT ? start_x > cursor_x : start_x < cursor_x)
- position = selection_start;
- // For word breaks, use the nearest word boundary in the appropriate
- // |direction|.
+ cursor = selection_start;
+ // Use the nearest word boundary in the proper |direction| for word breaks.
if (break_type == WORD_BREAK)
- position = GetAdjacentSelectionModel(position, break_type, direction);
+ cursor = GetAdjacentSelectionModel(cursor, break_type, direction);
+ // Use an adjacent selection model if the cursor is not at a valid position.
+ if (!IsValidCursorIndex(cursor.caret_pos()))
+ cursor = GetAdjacentSelectionModel(cursor, CHARACTER_BREAK, direction);
} else {
- position = GetAdjacentSelectionModel(position, break_type, direction);
+ cursor = GetAdjacentSelectionModel(cursor, break_type, direction);
}
if (select)
- position.set_selection_start(selection().start());
- MoveCursorTo(position);
+ cursor.set_selection_start(selection().start());
+ MoveCursorTo(cursor);
}
bool RenderText::MoveCursorTo(const SelectionModel& model) {
@@ -474,9 +555,8 @@ bool RenderText::MoveCursorTo(const SelectionModel& model) {
size_t text_length = text().length();
Range range(std::min(model.selection().start(), text_length),
std::min(model.caret_pos(), text_length));
- // The current model only supports caret positions at valid character indices.
- if (!IsCursorablePosition(range.start()) ||
- !IsCursorablePosition(range.end()))
+ // The current model only supports caret positions at valid cursor indices.
+ if (!IsValidCursorIndex(range.start()) || !IsValidCursorIndex(range.end()))
return false;
SelectionModel sel(range, model.caret_affinity());
bool changed = sel != selection_model_;
@@ -484,17 +564,11 @@ bool RenderText::MoveCursorTo(const SelectionModel& model) {
return changed;
}
-bool RenderText::MoveCursorTo(const Point& point, bool select) {
- SelectionModel position = FindCursorPosition(point);
- if (select)
- position.set_selection_start(selection().start());
- return MoveCursorTo(position);
-}
-
bool RenderText::SelectRange(const Range& range) {
Range sel(std::min(range.start(), text().length()),
std::min(range.end(), text().length()));
- if (!IsCursorablePosition(sel.start()) || !IsCursorablePosition(sel.end()))
+ // Allow selection bounds at valid indicies amid multi-character graphemes.
+ if (!IsValidLogicalIndex(sel.start()) || !IsValidLogicalIndex(sel.end()))
return false;
LogicalCursorDirection affinity =
(sel.is_reversed() || sel.is_empty()) ? CURSOR_FORWARD : CURSOR_BACKWARD;
@@ -688,7 +762,7 @@ void RenderText::Draw(Canvas* canvas) {
if (clip_to_display_rect()) {
Rect clip_rect(display_rect());
- clip_rect.Inset(ShadowValue::GetMargin(text_shadows_));
+ clip_rect.Inset(ShadowValue::GetMargin(shadows_));
canvas->Save();
canvas->ClipRect(clip_rect);
@@ -713,27 +787,19 @@ void RenderText::DrawCursor(Canvas* canvas, const SelectionModel& position) {
canvas->FillRect(GetCursorBounds(position, true), cursor_color_);
}
-void RenderText::DrawSelectedTextForDrag(Canvas* canvas) {
- EnsureLayout();
- const std::vector<Rect> sel = GetSubstringBounds(selection());
-
- // Override the selection color with black, and force the background to be
- // transparent so that it's rendered without subpixel antialiasing.
- const bool saved_background_is_transparent = background_is_transparent();
- const SkColor saved_selection_color = selection_color();
- set_background_is_transparent(true);
- set_selection_color(SK_ColorBLACK);
-
- for (size_t i = 0; i < sel.size(); ++i) {
- canvas->Save();
- canvas->ClipRect(sel[i]);
- DrawVisualText(canvas);
- canvas->Restore();
- }
-
- // Restore saved transparency and selection color.
- set_selection_color(saved_selection_color);
- set_background_is_transparent(saved_background_is_transparent);
+bool RenderText::IsValidLogicalIndex(size_t index) {
+ // Check that the index is at a valid code point (not mid-surrgate-pair) and
+ // that it's not truncated from the layout text (its glyph may be shown).
+ //
+ // Indices within truncated text are disallowed so users can easily interact
+ // with the underlying truncated text using the ellipsis as a proxy. This lets
+ // users select all text, select the truncated text, and transition from the
+ // last rendered glyph to the end of the text without getting invisible cursor
+ // positions nor needing unbounded arrow key presses to traverse the ellipsis.
+ return index == 0 || index == text().length() ||
+ (index < text().length() &&
+ (truncate_length_ == 0 || index < truncate_length_) &&
+ IsValidCodePointIndex(text(), index));
}
Rect RenderText::GetCursorBounds(const SelectionModel& caret,
@@ -743,9 +809,8 @@ Rect RenderText::GetCursorBounds(const SelectionModel& caret,
// the multiline size, eliminate its use here.
EnsureLayout();
-
size_t caret_pos = caret.caret_pos();
- DCHECK(IsCursorablePosition(caret_pos));
+ DCHECK(IsValidLogicalIndex(caret_pos));
// In overtype mode, ignore the affinity and always indicate that we will
// overtype the next character.
LogicalCursorDirection caret_affinity =
@@ -786,7 +851,7 @@ size_t RenderText::IndexOfAdjacentGrapheme(size_t index,
if (direction == CURSOR_FORWARD) {
while (index < text().length()) {
index++;
- if (IsCursorablePosition(index))
+ if (IsValidCursorIndex(index))
return index;
}
return text().length();
@@ -794,7 +859,7 @@ size_t RenderText::IndexOfAdjacentGrapheme(size_t index,
while (index > 0) {
index--;
- if (IsCursorablePosition(index))
+ if (IsValidCursorIndex(index))
return index;
}
return 0;
@@ -808,10 +873,6 @@ SelectionModel RenderText::GetSelectionModelForSelectionStart() {
sel.is_reversed() ? CURSOR_BACKWARD : CURSOR_FORWARD);
}
-void RenderText::SetTextShadows(const ShadowValues& shadows) {
- text_shadows_ = shadows;
-}
-
RenderText::RenderText()
: horizontal_alignment_(base::i18n::IsRTL() ? ALIGN_RIGHT : ALIGN_LEFT),
directionality_mode_(DIRECTIONALITY_FROM_TEXT),
@@ -830,9 +891,8 @@ RenderText::RenderText()
obscured_(false),
obscured_reveal_index_(-1),
truncate_length_(0),
+ elide_behavior_(TRUNCATE),
multiline_(false),
- fade_head_(false),
- fade_tail_(false),
background_is_transparent_(false),
clip_to_display_rect_(true),
baseline_(kInvalidBaseline),
@@ -872,7 +932,7 @@ void RenderText::SetSelectionModel(const SelectionModel& model) {
}
const base::string16& RenderText::GetLayoutText() const {
- return layout_text_.empty() ? text_ : layout_text_;
+ return layout_text_;
}
const BreakList<size_t>& RenderText::GetLineBreaks() {
@@ -1013,38 +1073,23 @@ Vector2d RenderText::GetAlignmentOffset(size_t line_number) {
}
void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) {
- if (multiline() || (!fade_head() && !fade_tail()))
+ const int width = display_rect().width();
+ if (multiline() || elide_behavior_ != FADE_TAIL || GetContentWidth() <= width)
return;
- const int display_width = display_rect().width();
-
- // If the text fits as-is, no need to fade.
- if (GetStringSize().width() <= display_width)
- return;
-
- int gradient_width = CalculateFadeGradientWidth(GetPrimaryFont(),
- display_width);
+ const int gradient_width = CalculateFadeGradientWidth(font_list(), width);
if (gradient_width == 0)
return;
- bool fade_left = fade_head();
- bool fade_right = fade_tail();
- // Under RTL, |fade_right| == |fade_head|.
- // TODO(asvitkine): This is currently not based on GetTextDirection() because
- // RenderTextWin does not return a direction that's based on
- // the text content.
- if (horizontal_alignment_ == ALIGN_RIGHT)
- std::swap(fade_left, fade_right);
-
Rect solid_part = display_rect();
Rect left_part;
Rect right_part;
- if (fade_left) {
+ 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);
}
- if (fade_right) {
+ 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);
@@ -1061,7 +1106,7 @@ void RenderText::ApplyFadeEffects(internal::SkiaTextRenderer* renderer) {
}
void RenderText::ApplyTextShadows(internal::SkiaTextRenderer* renderer) {
- skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(text_shadows_);
+ skia::RefPtr<SkDrawLooper> looper = CreateShadowDrawLooper(shadows_);
renderer->SetDrawLooper(looper.get());
}
@@ -1077,7 +1122,7 @@ bool RenderText::RangeContainsCaret(const Range& range,
void RenderText::MoveCursorTo(size_t position, bool select) {
size_t cursor = std::min(position, text().length());
- if (IsCursorablePosition(cursor))
+ if (IsValidCursorIndex(cursor))
SetSelectionModel(SelectionModel(
Range(select ? selection().start() : cursor, cursor),
(cursor == 0) ? CURSOR_FORWARD : CURSOR_BACKWARD));
@@ -1089,7 +1134,7 @@ void RenderText::UpdateLayoutText() {
if (obscured_) {
size_t obscured_text_length =
- static_cast<size_t>(gfx::UTF16IndexToOffset(text_, 0, text_.length()));
+ static_cast<size_t>(UTF16IndexToOffset(text_, 0, text_.length()));
layout_text_.assign(obscured_text_length, kPasswordReplacementChar);
if (obscured_reveal_index_ >= 0 &&
@@ -1103,19 +1148,122 @@ void RenderText::UpdateLayoutText() {
// Gets the index in |layout_text_| to be replaced.
const size_t cp_start =
- static_cast<size_t>(gfx::UTF16IndexToOffset(text_, 0, start));
+ static_cast<size_t>(UTF16IndexToOffset(text_, 0, start));
if (layout_text_.length() > cp_start)
layout_text_.replace(cp_start, 1, text_.substr(start, end - start));
}
+ } else {
+ layout_text_ = text_;
}
- const base::string16& text = obscured_ ? layout_text_ : text_;
+ const base::string16& text = layout_text_;
if (truncate_length_ > 0 && truncate_length_ < text.length()) {
// Truncate the text at a valid character break and append an ellipsis.
icu::StringCharacterIterator iter(text.c_str());
iter.setIndex32(truncate_length_ - 1);
- layout_text_.assign(text.substr(0, iter.getIndex()) + gfx::kEllipsisUTF16);
+ layout_text_.assign(text.substr(0, iter.getIndex()) + kEllipsisUTF16);
+ }
+
+ if (elide_behavior_ != TRUNCATE && elide_behavior_ != FADE_TAIL &&
+ display_rect_.width() > 0 && !layout_text_.empty() &&
+ GetContentWidth() > display_rect_.width()) {
+ // This doesn't trim styles so ellipsis may get rendered as a different
+ // style than the preceding text. See crbug.com/327850.
+ layout_text_.assign(ElideText(layout_text_));
+ }
+
+ ResetLayout();
+}
+
+// TODO(skanuj): Fix code duplication with ElideText in ui/gfx/text_elider.cc
+// See crbug.com/327846
+base::string16 RenderText::ElideText(const base::string16& text) {
+ const bool insert_ellipsis = (elide_behavior_ != TRUNCATE);
+ // Create a RenderText copy with attributes that affect the rendering width.
+ scoped_ptr<RenderText> render_text(CreateInstance());
+ render_text->SetFontList(font_list_);
+ render_text->SetDirectionalityMode(directionality_mode_);
+ render_text->SetCursorEnabled(cursor_enabled_);
+
+ render_text->styles_ = styles_;
+ render_text->colors_ = colors_;
+ render_text->SetText(text);
+ const int current_text_pixel_width = render_text->GetContentWidth();
+
+ const base::string16 ellipsis = base::string16(kEllipsisUTF16);
+ const bool elide_in_middle = false;
+ const bool elide_at_beginning = false;
+ StringSlicer slicer(text, ellipsis, elide_in_middle, elide_at_beginning);
+
+ // Pango will return 0 width for absurdly long strings. Cut the string in
+ // half and try again.
+ // This is caused by an int overflow in Pango (specifically, in
+ // pango_glyph_string_extents_range). It's actually more subtle than just
+ // returning 0, since on super absurdly long strings, the int can wrap and
+ // return positive numbers again. Detecting that is probably not worth it
+ // (eliding way too much from a ridiculous string is probably still
+ // ridiculous), but we should check other widths for bogus values as well.
+ if (current_text_pixel_width <= 0 && !text.empty())
+ return ElideText(slicer.CutString(text.length() / 2, insert_ellipsis));
+
+ if (current_text_pixel_width <= display_rect_.width())
+ return text;
+
+ render_text->SetText(base::string16());
+ render_text->SetText(ellipsis);
+ const int ellipsis_width = render_text->GetContentWidth();
+
+ if (insert_ellipsis && (ellipsis_width >= display_rect_.width()))
+ return base::string16();
+
+ // Use binary search to compute the elided text.
+ size_t lo = 0;
+ size_t hi = text.length() - 1;
+ const base::i18n::TextDirection text_direction = GetTextDirection();
+ for (size_t guess = (lo + hi) / 2; lo <= hi; guess = (lo + hi) / 2) {
+ // Restore styles and colors. They will be truncated to size by SetText.
+ render_text->styles_ = styles_;
+ render_text->colors_ = colors_;
+ base::string16 new_text = slicer.CutString(guess, false);
+ render_text->SetText(new_text);
+
+ // This has to be an additional step so that the ellipsis is rendered with
+ // same style as trailing part of the text.
+ if (insert_ellipsis) {
+ // When ellipsis follows text whose directionality is not the same as that
+ // of the whole text, it will be rendered with the directionality of the
+ // whole text. Since we want ellipsis to indicate continuation of the
+ // preceding text, we force the directionality of ellipsis to be same as
+ // the preceding text using LTR or RTL markers.
+ base::i18n::TextDirection trailing_text_direction =
+ base::i18n::GetLastStrongCharacterDirection(new_text);
+ new_text.append(ellipsis);
+ if (trailing_text_direction != text_direction) {
+ if (trailing_text_direction == base::i18n::LEFT_TO_RIGHT)
+ new_text += base::i18n::kLeftToRightMark;
+ else
+ new_text += base::i18n::kRightToLeftMark;
+ }
+ render_text->SetText(new_text);
+ }
+
+ // We check the width of the whole desired string at once to ensure we
+ // handle kerning/ligatures/etc. correctly.
+ const int guess_width = render_text->GetContentWidth();
+ if (guess_width == display_rect_.width())
+ break;
+ if (guess_width > display_rect_.width()) {
+ hi = guess - 1;
+ // Move back if we are on loop terminating condition, and guess is wider
+ // than available.
+ if (hi < lo)
+ lo = hi;
+ } else {
+ lo = guess + 1;
+ }
}
+
+ return render_text->text();
}
void RenderText::UpdateCachedBoundsAndOffset() {
@@ -1128,7 +1276,8 @@ void RenderText::UpdateCachedBoundsAndOffset() {
// the stale |display_offset_|. Applying |delta_offset| at the end of this
// function will set |cursor_bounds_| and |display_offset_| to correct values.
cached_bounds_and_offset_valid_ = true;
- cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_);
+ if (cursor_enabled())
+ cursor_bounds_ = GetCursorBounds(selection_model_, insert_mode_);
// Update |display_offset_| to ensure the current cursor is visible.
const int display_width = display_rect_.width();
diff --git a/chromium/ui/gfx/render_text.h b/chromium/ui/gfx/render_text.h
index 8696d690560..885df0a9b41 100644
--- a/chromium/ui/gfx/render_text.h
+++ b/chromium/ui/gfx/render_text.h
@@ -13,6 +13,7 @@
#include "base/gtest_prod_util.h"
#include "base/i18n/rtl.h"
+#include "base/memory/scoped_ptr.h"
#include "base/strings/string16.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -27,6 +28,7 @@
#include "ui/gfx/shadow_value.h"
#include "ui/gfx/size_f.h"
#include "ui/gfx/text_constants.h"
+#include "ui/gfx/text_elider.h"
#include "ui/gfx/vector2d.h"
class SkCanvas;
@@ -50,7 +52,10 @@ class SkiaTextRenderer {
~SkiaTextRenderer();
void SetDrawLooper(SkDrawLooper* draw_looper);
- void SetFontSmoothingSettings(bool enable_smoothing, bool enable_lcd_text);
+ void SetFontSmoothingSettings(bool antialiasing,
+ bool subpixel_rendering,
+ bool subpixel_positioning);
+ void SetFontHinting(SkPaint::Hinting hinting);
void SetTypeface(SkTypeface* typeface);
void SetTextSize(SkScalar size);
void SetFontFamilyWithStyle(const std::string& family, int font_style);
@@ -69,11 +74,36 @@ class SkiaTextRenderer {
// third_party/skia/src/core/SkTextFormatParams.h
void DrawDecorations(int x, int y, int width, bool underline, bool strike,
bool diagonal_strike);
+ // Finishes any ongoing diagonal strike run.
+ void EndDiagonalStrike();
void DrawUnderline(int x, int y, int width);
void DrawStrike(int x, int y, int width) const;
- void DrawDiagonalStrike(int x, int y, int width) const;
private:
+ // Helper class to draw a diagonal line with multiple pieces of different
+ // lengths and colors; to support text selection appearances.
+ class DiagonalStrike {
+ public:
+ DiagonalStrike(Canvas* canvas, Point start, const SkPaint& paint);
+ ~DiagonalStrike();
+
+ void AddPiece(int length, SkColor color);
+ void Draw();
+
+ private:
+ typedef std::pair<int, SkColor> Piece;
+
+ Canvas* canvas_;
+ SkMatrix matrix_;
+ const Point start_;
+ SkPaint paint_;
+ int total_length_;
+ std::vector<Piece> pieces_;
+
+ DISALLOW_COPY_AND_ASSIGN(DiagonalStrike);
+ };
+
+ Canvas* canvas_;
SkCanvas* canvas_skia_;
bool started_drawing_;
SkPaint paint_;
@@ -81,6 +111,7 @@ class SkiaTextRenderer {
skia::RefPtr<SkShader> deferred_fade_shader_;
SkScalar underline_thickness_;
SkScalar underline_position_;
+ scoped_ptr<DiagonalStrike> diagonal_;
DISALLOW_COPY_AND_ASSIGN(SkiaTextRenderer);
};
@@ -146,6 +177,10 @@ struct Line {
int baseline;
};
+// Creates an SkTypeface from a font |family| name and a |gfx::Font::FontStyle|.
+skia::RefPtr<SkTypeface> CreateSkiaTypeface(const std::string& family,
+ int style);
+
} // namespace internal
// RenderText represents an abstract model of styled text and its corresponding
@@ -156,7 +191,7 @@ class GFX_EXPORT RenderText {
public:
virtual ~RenderText();
- // Creates a platform-specific RenderText instance.
+ // Creates a platform-specific or cross-platform RenderText instance.
static RenderText* CreateInstance();
const base::string16& text() const { return text_; }
@@ -169,13 +204,6 @@ class GFX_EXPORT RenderText {
const FontList& font_list() const { return font_list_; }
void SetFontList(const FontList& font_list);
- void SetFont(const Font& font);
-
- // Set the font size to |size| in pixels.
- void SetFontSize(int size);
-
- // Get the first font in |font_list_|.
- const Font& GetPrimaryFont() const;
bool cursor_enabled() const { return cursor_enabled_; }
void SetCursorEnabled(bool cursor_enabled);
@@ -227,14 +255,14 @@ class GFX_EXPORT RenderText {
// WARNING: Only use this for system limits, it lacks complex text support.
void set_truncate_length(size_t length) { truncate_length_ = length; }
+ // Elides the text to fit in |display_rect| according to the specified
+ // |elide_behavior|. |ELIDE_MIDDLE| is not supported. If a truncate length and
+ // an elide mode are specified, the shorter of the two will be applicable.
+ void SetElideBehavior(ElideBehavior elide_behavior);
+
const Rect& display_rect() const { return display_rect_; }
void SetDisplayRect(const Rect& r);
- void set_fade_head(bool fade_head) { fade_head_ = fade_head; }
- bool fade_head() const { return fade_head_; }
- void set_fade_tail(bool fade_tail) { fade_tail_ = fade_tail; }
- bool fade_tail() const { return fade_tail_; }
-
bool background_is_transparent() const { return background_is_transparent_; }
void set_background_is_transparent(bool transparent) {
background_is_transparent_ = transparent;
@@ -261,11 +289,6 @@ class GFX_EXPORT RenderText {
// grapheme boundary), it is a no-op and returns false.
bool MoveCursorTo(const SelectionModel& selection_model);
- // Move the cursor to the position associated with the clicked point.
- // If |select| is false, the selection start is moved to the same position.
- // Returns true if the cursor position or selection range changed.
- bool MoveCursorTo(const Point& point, bool select);
-
// Set the selection_model_ based on |range|.
// If the |range| start or end is greater than text length, it is modified
// to be the text length.
@@ -320,9 +343,8 @@ class GFX_EXPORT RenderText {
VisualCursorDirection GetVisualDirectionOfLogicalEnd();
// Returns the size required to display the current string (which is the
- // wrapped size in multiline mode). Note that this returns the raw size of the
- // string, which does not include the cursor or the margin area of text
- // shadows.
+ // wrapped size in multiline mode). The returned size does not include space
+ // reserved for the cursor or the offset text shadows.
virtual Size GetStringSize() = 0;
// This is same as GetStringSize except that fractional size is returned.
@@ -347,16 +369,16 @@ class GFX_EXPORT RenderText {
// Draws a cursor at |position|.
void DrawCursor(Canvas* canvas, const SelectionModel& position);
- // Draw the selected text without a cursor or selection highlight. Subpixel
- // antialiasing is disabled and foreground color is forced to black.
- void DrawSelectedTextForDrag(Canvas* canvas);
-
// Gets the SelectionModel from a visual point in local coordinates.
virtual SelectionModel FindCursorPosition(const Point& point) = 0;
- // Return true if cursor can appear in front of the character at |position|,
- // which means it is a grapheme boundary or the first character in the text.
- virtual bool IsCursorablePosition(size_t position) = 0;
+ // Returns true if the position is a valid logical index into text(), and is
+ // also a valid grapheme boundary, which may be used as a cursor position.
+ virtual bool IsValidCursorIndex(size_t index) = 0;
+
+ // Returns true if the position is a valid logical index into text(). Indices
+ // amid multi-character graphemes are allowed here, unlike IsValidCursorIndex.
+ virtual bool IsValidLogicalIndex(size_t index);
// Get the visual bounds of a cursor at |caret|. These bounds typically
// represent a vertical line if |insert_mode| is true. Pass false for
@@ -364,8 +386,7 @@ class GFX_EXPORT RenderText {
// are in local coordinates, but may be outside the visible region if the text
// is longer than the textfield. Subsequent text, cursor, or bounds changes
// may invalidate returned values. Note that |caret| must be placed at
- // grapheme boundary, that is, |IsCursorablePosition(caret.caret_pos())| must
- // return true.
+ // grapheme boundary, i.e. caret.caret_pos() must be a cursorable position.
Rect GetCursorBounds(const SelectionModel& caret, bool insert_mode);
// Compute the current cursor bounds, panning the text to show the cursor in
@@ -374,10 +395,9 @@ class GFX_EXPORT RenderText {
const Rect& GetUpdatedCursorBounds();
// Given an |index| in text(), return the next or previous grapheme boundary
- // in logical order (that is, the nearest index for which
- // |IsCursorablePosition(index)| returns true). The return value is in the
- // range 0 to text().length() inclusive (the input is clamped if it is out of
- // that range). Always moves by at least one character index unless the
+ // in logical order (i.e. the nearest cursorable index). The return value is
+ // in the range 0 to text().length() inclusive (the input is clamped if it is
+ // out of that range). Always moves by at least one character index unless the
// supplied index is already at the boundary of the string.
size_t IndexOfAdjacentGrapheme(size_t index,
LogicalCursorDirection direction);
@@ -387,7 +407,7 @@ class GFX_EXPORT RenderText {
SelectionModel GetSelectionModelForSelectionStart();
// Sets shadows to drawn with text.
- void SetTextShadows(const ShadowValues& shadows);
+ void set_shadows(const ShadowValues& shadows) { shadows_ = shadows; }
typedef std::pair<Font, Range> FontSpan;
// For testing purposes, returns which fonts were chosen for which parts of
@@ -396,6 +416,12 @@ class GFX_EXPORT RenderText {
// chosen.
virtual std::vector<FontSpan> GetFontSpansForTesting() = 0;
+ // Gets the horizontal bounds (relative to the left of the text, not the view)
+ // of the glyph starting at |index|. If the glyph is RTL then the returned
+ // Range will have is_reversed() true. (This does not return a Rect because a
+ // Rect can't have a negative width.)
+ virtual Range GetGlyphBounds(size_t index) = 0;
+
protected:
RenderText();
@@ -460,12 +486,6 @@ class GFX_EXPORT RenderText {
// Sets the selection model, the argument is assumed to be valid.
virtual void SetSelectionModel(const SelectionModel& model);
- // Get the horizontal bounds (relative to the left of the text, not the view)
- // of the glyph starting at |index|. If the glyph is RTL then the returned
- // Range will have is_reversed() true. (This does not return a Rect because a
- // Rect can't have a negative width.)
- virtual Range GetGlyphBounds(size_t index) = 0;
-
// Get the visual bounds containing the logical substring within the |range|.
// If |range| is empty, the result is empty. These bounds could be visually
// discontinuous if the substring is split by a LTR/RTL level change.
@@ -508,12 +528,10 @@ class GFX_EXPORT RenderText {
Point ToTextPoint(const Point& point);
Point ToViewPoint(const Point& point);
- // Convert a text space x-coordinate range to corresponding rects in view
- // space.
+ // Convert a text space x-coordinate range to rects in view space.
std::vector<Rect> TextBoundsToViewBounds(const Range& x);
- // Returns the line offset from the origin, accounting for text alignment
- // only.
+ // Returns the line offset from the origin, accounts for text alignment only.
Vector2d GetAlignmentOffset(size_t line_number);
// Applies fade effects to |renderer|.
@@ -535,6 +553,8 @@ class GFX_EXPORT RenderText {
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, ApplyColorAndStyle);
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, ObscuredText);
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, RevealObscuredText);
+ FRIEND_TEST_ALL_PREFIXES(RenderTextTest, ElidedText);
+ FRIEND_TEST_ALL_PREFIXES(RenderTextTest, ElidedObscuredText);
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, TruncatedText);
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, TruncatedObscuredText);
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, GraphemePositions);
@@ -545,6 +565,11 @@ class GFX_EXPORT RenderText {
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_NormalWidth);
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_SufficientWidth);
FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_Newline);
+ FRIEND_TEST_ALL_PREFIXES(RenderTextTest, GlyphBounds);
+ FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_GlyphBounds);
+
+ // Creates a platform-specific RenderText instance.
+ static RenderText* CreateNativeInstance();
// Set the cursor to |position|, with the caret trailing the previous
// grapheme, or if there is no previous grapheme, leading the cursor position.
@@ -556,6 +581,10 @@ class GFX_EXPORT RenderText {
// Updates |layout_text_| if the text is obscured or truncated.
void UpdateLayoutText();
+ // Elides |text| to fit in the |display_rect_| with given |elide_behavior_|.
+ // See ElideText in ui/gfx/text_elider.cc for reference.
+ base::string16 ElideText(const base::string16& text);
+
// Update the cached bounds and display offset to ensure that the current
// cursor is within the visible display area.
void UpdateCachedBoundsAndOffset();
@@ -628,6 +657,9 @@ class GFX_EXPORT RenderText {
// The maximum length of text to display, 0 forgoes a hard limit.
size_t truncate_length_;
+ // The behavior for eliding, fading, or truncating.
+ ElideBehavior elide_behavior_;
+
// The obscured and/or truncated text that will be displayed.
base::string16 layout_text_;
@@ -635,10 +667,6 @@ class GFX_EXPORT RenderText {
// |display_rect_| as the width cap.
bool multiline_;
- // Fade text head and/or tail, if text doesn't fit into |display_rect_|.
- bool fade_head_;
- bool fade_tail_;
-
// Is the background transparent (either partially or fully)?
bool background_is_transparent_;
@@ -665,7 +693,7 @@ class GFX_EXPORT RenderText {
bool cached_bounds_and_offset_valid_;
// Text shadows to be drawn.
- ShadowValues text_shadows_;
+ ShadowValues shadows_;
// A list of valid layout text line break positions.
BreakList<size_t> line_breaks_;
diff --git a/chromium/ui/gfx/render_text_harfbuzz.cc b/chromium/ui/gfx/render_text_harfbuzz.cc
new file mode 100644
index 00000000000..3d9bf58141e
--- /dev/null
+++ b/chromium/ui/gfx/render_text_harfbuzz.cc
@@ -0,0 +1,1010 @@
+// 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/render_text_harfbuzz.h"
+
+#include <map>
+
+#include "base/debug/leak_annotations.h"
+#include "base/i18n/bidi_line_iterator.h"
+#include "base/i18n/break_iterator.h"
+#include "base/i18n/char_iterator.h"
+#include "base/lazy_instance.h"
+#include "third_party/harfbuzz-ng/src/hb.h"
+#include "third_party/icu/source/common/unicode/ubidi.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "third_party/skia/include/core/SkTypeface.h"
+#include "ui/gfx/canvas.h"
+#include "ui/gfx/utf16_indexing.h"
+
+#if defined(OS_WIN)
+#include "ui/gfx/font_smoothing_win.h"
+#endif
+
+namespace gfx {
+
+namespace {
+
+// The maximum number of scripts a Unicode character can belong to. This value
+// is arbitrarily chosen to be a good limit because it is unlikely for a single
+// character to belong to more scripts.
+const size_t kMaxScripts = 5;
+
+// Maps from code points to glyph indices in a font.
+typedef std::map<uint32_t, uint16_t> GlyphCache;
+
+// Font data provider for HarfBuzz using Skia. Copied from Blink.
+// TODO(ckocagil): Eliminate the duplication. http://crbug.com/368375
+struct FontData {
+ FontData(GlyphCache* glyph_cache) : glyph_cache_(glyph_cache) {}
+
+ SkPaint paint_;
+ GlyphCache* glyph_cache_;
+};
+
+hb_position_t SkiaScalarToHarfBuzzPosition(SkScalar value) {
+ return SkScalarToFixed(value);
+}
+
+// Deletes the object at the given pointer after casting it to the given type.
+template<typename Type>
+void DeleteByType(void* data) {
+ Type* typed_data = reinterpret_cast<Type*>(data);
+ delete typed_data;
+}
+
+template<typename Type>
+void DeleteArrayByType(void* data) {
+ Type* typed_data = reinterpret_cast<Type*>(data);
+ delete[] typed_data;
+}
+
+// Outputs the |width| and |extents| of the glyph with index |codepoint| in
+// |paint|'s font.
+void GetGlyphWidthAndExtents(SkPaint* paint,
+ hb_codepoint_t codepoint,
+ hb_position_t* width,
+ hb_glyph_extents_t* extents) {
+ DCHECK_LE(codepoint, 0xFFFFU);
+ paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ SkScalar sk_width;
+ SkRect sk_bounds;
+ uint16_t glyph = codepoint;
+
+ paint->getTextWidths(&glyph, sizeof(glyph), &sk_width, &sk_bounds);
+ if (width)
+ *width = SkiaScalarToHarfBuzzPosition(sk_width);
+ if (extents) {
+ // Invert y-axis because Skia is y-grows-down but we set up HarfBuzz to be
+ // y-grows-up.
+ extents->x_bearing = SkiaScalarToHarfBuzzPosition(sk_bounds.fLeft);
+ extents->y_bearing = SkiaScalarToHarfBuzzPosition(-sk_bounds.fTop);
+ extents->width = SkiaScalarToHarfBuzzPosition(sk_bounds.width());
+ extents->height = SkiaScalarToHarfBuzzPosition(-sk_bounds.height());
+ }
+}
+
+// Writes the |glyph| index for the given |unicode| code point. Returns whether
+// the glyph exists, i.e. it is not a missing glyph.
+hb_bool_t GetGlyph(hb_font_t* font,
+ void* data,
+ hb_codepoint_t unicode,
+ hb_codepoint_t variation_selector,
+ hb_codepoint_t* glyph,
+ void* user_data) {
+ FontData* font_data = reinterpret_cast<FontData*>(data);
+ GlyphCache* cache = font_data->glyph_cache_;
+
+ bool exists = cache->count(unicode) != 0;
+ if (!exists) {
+ SkPaint* paint = &font_data->paint_;
+ paint->setTextEncoding(SkPaint::kUTF32_TextEncoding);
+ paint->textToGlyphs(&unicode, sizeof(hb_codepoint_t), &(*cache)[unicode]);
+ }
+ *glyph = (*cache)[unicode];
+ return !!*glyph;
+}
+
+// Returns the horizontal advance value of the |glyph|.
+hb_position_t GetGlyphHorizontalAdvance(hb_font_t* font,
+ void* data,
+ hb_codepoint_t glyph,
+ void* user_data) {
+ FontData* font_data = reinterpret_cast<FontData*>(data);
+ hb_position_t advance = 0;
+
+ GetGlyphWidthAndExtents(&font_data->paint_, glyph, &advance, 0);
+ return advance;
+}
+
+hb_bool_t GetGlyphHorizontalOrigin(hb_font_t* font,
+ void* data,
+ hb_codepoint_t glyph,
+ hb_position_t* x,
+ hb_position_t* y,
+ void* user_data) {
+ // Just return true, like the HarfBuzz-FreeType implementation.
+ return true;
+}
+
+hb_position_t GetGlyphKerning(FontData* font_data,
+ hb_codepoint_t first_glyph,
+ hb_codepoint_t second_glyph) {
+ SkTypeface* typeface = font_data->paint_.getTypeface();
+ const uint16_t glyphs[2] = { static_cast<uint16_t>(first_glyph),
+ static_cast<uint16_t>(second_glyph) };
+ int32_t kerning_adjustments[1] = { 0 };
+
+ if (!typeface->getKerningPairAdjustments(glyphs, 2, kerning_adjustments))
+ return 0;
+
+ SkScalar upm = SkIntToScalar(typeface->getUnitsPerEm());
+ SkScalar size = font_data->paint_.getTextSize();
+ return SkiaScalarToHarfBuzzPosition(
+ SkScalarMulDiv(SkIntToScalar(kerning_adjustments[0]), size, upm));
+}
+
+hb_position_t GetGlyphHorizontalKerning(hb_font_t* font,
+ void* data,
+ hb_codepoint_t left_glyph,
+ hb_codepoint_t right_glyph,
+ void* user_data) {
+ FontData* font_data = reinterpret_cast<FontData*>(data);
+ if (font_data->paint_.isVerticalText()) {
+ // We don't support cross-stream kerning.
+ return 0;
+ }
+
+ return GetGlyphKerning(font_data, left_glyph, right_glyph);
+}
+
+hb_position_t GetGlyphVerticalKerning(hb_font_t* font,
+ void* data,
+ hb_codepoint_t top_glyph,
+ hb_codepoint_t bottom_glyph,
+ void* user_data) {
+ FontData* font_data = reinterpret_cast<FontData*>(data);
+ if (!font_data->paint_.isVerticalText()) {
+ // We don't support cross-stream kerning.
+ return 0;
+ }
+
+ return GetGlyphKerning(font_data, top_glyph, bottom_glyph);
+}
+
+// Writes the |extents| of |glyph|.
+hb_bool_t GetGlyphExtents(hb_font_t* font,
+ void* data,
+ hb_codepoint_t glyph,
+ hb_glyph_extents_t* extents,
+ void* user_data) {
+ FontData* font_data = reinterpret_cast<FontData*>(data);
+
+ GetGlyphWidthAndExtents(&font_data->paint_, glyph, 0, extents);
+ return true;
+}
+
+class FontFuncs {
+ public:
+ FontFuncs() : font_funcs_(hb_font_funcs_create()) {
+ hb_font_funcs_set_glyph_func(font_funcs_, GetGlyph, 0, 0);
+ hb_font_funcs_set_glyph_h_advance_func(
+ font_funcs_, GetGlyphHorizontalAdvance, 0, 0);
+ hb_font_funcs_set_glyph_h_kerning_func(
+ font_funcs_, GetGlyphHorizontalKerning, 0, 0);
+ hb_font_funcs_set_glyph_h_origin_func(
+ font_funcs_, GetGlyphHorizontalOrigin, 0, 0);
+ hb_font_funcs_set_glyph_v_kerning_func(
+ font_funcs_, GetGlyphVerticalKerning, 0, 0);
+ hb_font_funcs_set_glyph_extents_func(
+ font_funcs_, GetGlyphExtents, 0, 0);
+ hb_font_funcs_make_immutable(font_funcs_);
+ }
+
+ ~FontFuncs() {
+ hb_font_funcs_destroy(font_funcs_);
+ }
+
+ hb_font_funcs_t* get() { return font_funcs_; }
+
+ private:
+ hb_font_funcs_t* font_funcs_;
+
+ DISALLOW_COPY_AND_ASSIGN(FontFuncs);
+};
+
+base::LazyInstance<FontFuncs>::Leaky g_font_funcs = LAZY_INSTANCE_INITIALIZER;
+
+// Returns the raw data of the font table |tag|.
+hb_blob_t* GetFontTable(hb_face_t* face, hb_tag_t tag, void* user_data) {
+ SkTypeface* typeface = reinterpret_cast<SkTypeface*>(user_data);
+
+ const size_t table_size = typeface->getTableSize(tag);
+ if (!table_size)
+ return 0;
+
+ scoped_ptr<char[]> buffer(new char[table_size]);
+ if (!buffer)
+ return 0;
+ size_t actual_size = typeface->getTableData(tag, 0, table_size, buffer.get());
+ if (table_size != actual_size)
+ return 0;
+
+ char* buffer_raw = buffer.release();
+ return hb_blob_create(buffer_raw, table_size, HB_MEMORY_MODE_WRITABLE,
+ buffer_raw, DeleteArrayByType<char>);
+}
+
+void UnrefSkTypeface(void* data) {
+ SkTypeface* skia_face = reinterpret_cast<SkTypeface*>(data);
+ SkSafeUnref(skia_face);
+}
+
+// Creates a HarfBuzz face from the given Skia face.
+hb_face_t* CreateHarfBuzzFace(SkTypeface* skia_face) {
+ SkSafeRef(skia_face);
+ hb_face_t* face = hb_face_create_for_tables(GetFontTable, skia_face,
+ UnrefSkTypeface);
+ DCHECK(face);
+ return face;
+}
+
+// Creates a HarfBuzz font from the given Skia face and text size.
+hb_font_t* CreateHarfBuzzFont(SkTypeface* skia_face, int text_size) {
+ typedef std::pair<hb_face_t*, GlyphCache> FaceCache;
+
+ // TODO(ckocagil): This shouldn't grow indefinitely. Maybe use base::MRUCache?
+ static std::map<SkFontID, FaceCache> face_caches;
+
+ FaceCache* face_cache = &face_caches[skia_face->uniqueID()];
+ if (face_cache->first == 0) {
+ // These HarfBuzz faces live indefinitely and are intentionally leaked.
+ ANNOTATE_SCOPED_MEMORY_LEAK;
+ hb_face_t* harfbuzz_face = CreateHarfBuzzFace(skia_face);
+ *face_cache = FaceCache(harfbuzz_face, GlyphCache());
+ }
+
+ hb_font_t* harfbuzz_font = hb_font_create(face_cache->first);
+ // TODO(ckocagil): Investigate whether disabling hinting here has any effect
+ // on text quality.
+ int upem = hb_face_get_upem(face_cache->first);
+ hb_font_set_scale(harfbuzz_font, upem, upem);
+ FontData* hb_font_data = new FontData(&face_cache->second);
+ hb_font_data->paint_.setTypeface(skia_face);
+ hb_font_data->paint_.setTextSize(text_size);
+ hb_font_set_funcs(harfbuzz_font, g_font_funcs.Get().get(), hb_font_data,
+ DeleteByType<FontData>);
+ hb_font_make_immutable(harfbuzz_font);
+ return harfbuzz_font;
+}
+
+// Returns true if characters of |block_code| may trigger font fallback.
+bool IsUnusualBlockCode(UBlockCode block_code) {
+ return block_code == UBLOCK_GEOMETRIC_SHAPES ||
+ block_code == UBLOCK_MISCELLANEOUS_SYMBOLS;
+}
+
+// Returns the index of the first unusual character after a usual character or
+// vice versa. Unusual characters are defined by |IsUnusualBlockCode|.
+size_t FindUnusualCharacter(const base::string16& text,
+ size_t run_start,
+ size_t run_break) {
+ const int32 run_length = static_cast<int32>(run_break - run_start);
+ base::i18n::UTF16CharIterator iter(text.c_str() + run_start,
+ run_length);
+ const UBlockCode first_block_code = ublock_getCode(iter.get());
+ const bool first_block_unusual = IsUnusualBlockCode(first_block_code);
+ while (iter.Advance() && iter.array_pos() < run_length) {
+ const UBlockCode current_block_code = ublock_getCode(iter.get());
+ if (current_block_code != first_block_code &&
+ (first_block_unusual || IsUnusualBlockCode(current_block_code))) {
+ return run_start + iter.array_pos();
+ }
+ }
+ return run_break;
+}
+
+// If the given scripts match, returns the one that isn't USCRIPT_COMMON or
+// USCRIPT_INHERITED, i.e. the more specific one. Otherwise returns
+// USCRIPT_INVALID_CODE.
+UScriptCode ScriptIntersect(UScriptCode first, UScriptCode second) {
+ if (first == second ||
+ (second > USCRIPT_INVALID_CODE && second <= USCRIPT_INHERITED)) {
+ return first;
+ }
+ if (first > USCRIPT_INVALID_CODE && first <= USCRIPT_INHERITED)
+ return second;
+ return USCRIPT_INVALID_CODE;
+}
+
+// Writes the script and the script extensions of the character with the
+// Unicode |codepoint|. Returns the number of written scripts.
+int GetScriptExtensions(UChar32 codepoint, UScriptCode* scripts) {
+ UErrorCode icu_error = U_ZERO_ERROR;
+ // ICU documentation incorrectly states that the result of
+ // |uscript_getScriptExtensions| will contain the regular script property.
+ // Write the character's script property to the first element.
+ scripts[0] = uscript_getScript(codepoint, &icu_error);
+ if (U_FAILURE(icu_error))
+ return 0;
+ // Fill the rest of |scripts| with the extensions.
+ int count = uscript_getScriptExtensions(codepoint, scripts + 1,
+ kMaxScripts - 1, &icu_error);
+ if (U_FAILURE(icu_error))
+ count = 0;
+ return count + 1;
+}
+
+// Intersects the script extensions set of |codepoint| with |result| and writes
+// to |result|, reading and updating |result_size|.
+void ScriptSetIntersect(UChar32 codepoint,
+ UScriptCode* result,
+ size_t* result_size) {
+ UScriptCode scripts[kMaxScripts] = { USCRIPT_INVALID_CODE };
+ int count = GetScriptExtensions(codepoint, scripts);
+
+ size_t out_size = 0;
+
+ for (size_t i = 0; i < *result_size; ++i) {
+ for (int j = 0; j < count; ++j) {
+ UScriptCode intersection = ScriptIntersect(result[i], scripts[j]);
+ if (intersection != USCRIPT_INVALID_CODE) {
+ result[out_size++] = intersection;
+ break;
+ }
+ }
+ }
+
+ *result_size = out_size;
+}
+
+// Find the longest sequence of characters from 0 and up to |length| that
+// have at least one common UScriptCode value. Writes the common script value to
+// |script| and returns the length of the sequence. Takes the characters' script
+// extensions into account. http://www.unicode.org/reports/tr24/#ScriptX
+//
+// Consider 3 characters with the script values {Kana}, {Hira, Kana}, {Kana}.
+// Without script extensions only the first script in each set would be taken
+// into account, resulting in 3 runs where 1 would be enough.
+// TODO(ckocagil): Write a unit test for the case above.
+int ScriptInterval(const base::string16& text,
+ size_t start,
+ size_t length,
+ UScriptCode* script) {
+ DCHECK_GT(length, 0U);
+
+ UScriptCode scripts[kMaxScripts] = { USCRIPT_INVALID_CODE };
+
+ base::i18n::UTF16CharIterator char_iterator(text.c_str() + start, length);
+ size_t scripts_size = GetScriptExtensions(char_iterator.get(), scripts);
+ *script = scripts[0];
+
+ while (char_iterator.Advance()) {
+ ScriptSetIntersect(char_iterator.get(), scripts, &scripts_size);
+ if (scripts_size == 0U)
+ return char_iterator.array_pos();
+ *script = scripts[0];
+ }
+
+ return length;
+}
+
+// A port of hb_icu_script_to_script because harfbuzz on CrOS is built without
+// hb-icu. See http://crbug.com/356929
+inline hb_script_t ICUScriptToHBScript(UScriptCode script) {
+ if (script == USCRIPT_INVALID_CODE)
+ return HB_SCRIPT_INVALID;
+ return hb_script_from_string(uscript_getShortName(script), -1);
+}
+
+} // namespace
+
+namespace internal {
+
+TextRunHarfBuzz::TextRunHarfBuzz()
+ : width(0),
+ preceding_run_widths(0),
+ is_rtl(false),
+ level(0),
+ script(USCRIPT_INVALID_CODE),
+ glyph_count(-1),
+ font_size(0),
+ font_style(0),
+ strike(false),
+ diagonal_strike(false),
+ underline(false) {}
+
+TextRunHarfBuzz::~TextRunHarfBuzz() {}
+
+size_t TextRunHarfBuzz::CharToGlyph(size_t pos) const {
+ DCHECK(range.start() <= pos && pos < range.end());
+
+ if (!is_rtl) {
+ size_t cluster_start = 0;
+ for (size_t i = 1; i < glyph_count && pos >= glyph_to_char[i]; ++i)
+ if (glyph_to_char[i] != glyph_to_char[i - 1])
+ cluster_start = i;
+ return cluster_start;
+ }
+
+ for (size_t i = 0; i < glyph_count; ++i) {
+ if (pos >= glyph_to_char[i])
+ return i;
+ }
+ NOTREACHED();
+ return 0;
+}
+
+Range TextRunHarfBuzz::CharRangeToGlyphRange(const Range& char_range) const {
+ DCHECK(range.Contains(char_range));
+ DCHECK(!char_range.is_reversed());
+ DCHECK(!char_range.is_empty());
+
+ size_t first = 0;
+ size_t last = 0;
+
+ if (is_rtl) {
+ // For RTL runs, we subtract 1 from |char_range| to get the leading edges.
+ last = CharToGlyph(char_range.end() - 1);
+ // Loop until we find a non-empty glyph range. For multi-character clusters,
+ // the loop is needed to find the cluster end. Do the same for LTR below.
+ for (size_t i = char_range.start(); i > range.start(); --i) {
+ first = CharToGlyph(i - 1);
+ if (first != last)
+ return Range(last, first);
+ }
+ return Range(last, glyph_count);
+ }
+
+ first = CharToGlyph(char_range.start());
+ for (size_t i = char_range.end(); i < range.end(); ++i) {
+ last = CharToGlyph(i);
+ if (first != last)
+ return Range(first, last);
+ }
+ return Range(first, glyph_count);
+}
+
+// Returns whether the given shaped run contains any missing glyphs.
+bool TextRunHarfBuzz::HasMissingGlyphs() const {
+ static const int kMissingGlyphId = 0;
+ for (size_t i = 0; i < glyph_count; ++i) {
+ if (glyphs[i] == kMissingGlyphId)
+ return true;
+ }
+ return false;
+}
+
+int TextRunHarfBuzz::GetGlyphXBoundary(size_t text_index, bool trailing) const {
+ if (text_index == range.end()) {
+ trailing = true;
+ --text_index;
+ }
+ Range glyph_range = CharRangeToGlyphRange(Range(text_index, text_index + 1));
+ const size_t glyph_pos = (is_rtl == trailing) ?
+ glyph_range.start() : glyph_range.end();
+ const int x = glyph_pos < glyph_count ?
+ SkScalarRoundToInt(positions[glyph_pos].x()) : width;
+ return preceding_run_widths + x;
+}
+
+} // namespace internal
+
+RenderTextHarfBuzz::RenderTextHarfBuzz()
+ : RenderText(),
+ needs_layout_(false) {}
+
+RenderTextHarfBuzz::~RenderTextHarfBuzz() {}
+
+Size RenderTextHarfBuzz::GetStringSize() {
+ EnsureLayout();
+ return lines()[0].size;
+}
+
+SelectionModel RenderTextHarfBuzz::FindCursorPosition(const Point& point) {
+ EnsureLayout();
+
+ int x = ToTextPoint(point).x();
+ int offset = 0;
+ size_t run_index = GetRunContainingXCoord(x, &offset);
+ if (run_index >= runs_.size())
+ return EdgeSelectionModel((x < 0) ? CURSOR_LEFT : CURSOR_RIGHT);
+ const internal::TextRunHarfBuzz& run = *runs_[run_index];
+
+ for (size_t i = 0; i < run.glyph_count; ++i) {
+ const SkScalar end =
+ i + 1 == run.glyph_count ? run.width : run.positions[i + 1].x();
+ const SkScalar middle = (end + run.positions[i].x()) / 2;
+
+ if (offset < middle) {
+ return SelectionModel(LayoutIndexToTextIndex(
+ run.glyph_to_char[i] + (run.is_rtl ? 1 : 0)),
+ (run.is_rtl ? CURSOR_BACKWARD : CURSOR_FORWARD));
+ }
+ if (offset < end) {
+ return SelectionModel(LayoutIndexToTextIndex(
+ run.glyph_to_char[i] + (run.is_rtl ? 0 : 1)),
+ (run.is_rtl ? CURSOR_FORWARD : CURSOR_BACKWARD));
+ }
+ }
+ return EdgeSelectionModel(CURSOR_RIGHT);
+}
+
+std::vector<RenderText::FontSpan> RenderTextHarfBuzz::GetFontSpansForTesting() {
+ NOTIMPLEMENTED();
+ return std::vector<RenderText::FontSpan>();
+}
+
+int RenderTextHarfBuzz::GetLayoutTextBaseline() {
+ EnsureLayout();
+ return lines()[0].baseline;
+}
+
+SelectionModel RenderTextHarfBuzz::AdjacentCharSelectionModel(
+ const SelectionModel& selection,
+ VisualCursorDirection direction) {
+ DCHECK(!needs_layout_);
+ internal::TextRunHarfBuzz* run;
+ size_t run_index = GetRunContainingCaret(selection);
+ if (run_index >= runs_.size()) {
+ // The cursor is not in any run: we're at the visual and logical edge.
+ SelectionModel edge = EdgeSelectionModel(direction);
+ if (edge.caret_pos() == selection.caret_pos())
+ return edge;
+ int visual_index = (direction == CURSOR_RIGHT) ? 0 : runs_.size() - 1;
+ run = runs_[visual_to_logical_[visual_index]];
+ } else {
+ // If the cursor is moving within the current run, just move it by one
+ // grapheme in the appropriate direction.
+ run = runs_[run_index];
+ size_t caret = selection.caret_pos();
+ bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT);
+ if (forward_motion) {
+ if (caret < LayoutIndexToTextIndex(run->range.end())) {
+ caret = IndexOfAdjacentGrapheme(caret, CURSOR_FORWARD);
+ return SelectionModel(caret, CURSOR_BACKWARD);
+ }
+ } else {
+ if (caret > LayoutIndexToTextIndex(run->range.start())) {
+ caret = IndexOfAdjacentGrapheme(caret, CURSOR_BACKWARD);
+ return SelectionModel(caret, CURSOR_FORWARD);
+ }
+ }
+ // The cursor is at the edge of a run; move to the visually adjacent run.
+ int visual_index = logical_to_visual_[run_index];
+ visual_index += (direction == CURSOR_LEFT) ? -1 : 1;
+ if (visual_index < 0 || visual_index >= static_cast<int>(runs_.size()))
+ return EdgeSelectionModel(direction);
+ run = runs_[visual_to_logical_[visual_index]];
+ }
+ bool forward_motion = run->is_rtl == (direction == CURSOR_LEFT);
+ return forward_motion ? FirstSelectionModelInsideRun(run) :
+ LastSelectionModelInsideRun(run);
+}
+
+SelectionModel RenderTextHarfBuzz::AdjacentWordSelectionModel(
+ const SelectionModel& selection,
+ VisualCursorDirection direction) {
+ // TODO(ckocagil): This implementation currently matches RenderTextWin, but it
+ // should match the native behavior on other platforms.
+ if (obscured())
+ return EdgeSelectionModel(direction);
+
+ base::i18n::BreakIterator iter(text(), base::i18n::BreakIterator::BREAK_WORD);
+ bool success = iter.Init();
+ DCHECK(success);
+ if (!success)
+ return selection;
+
+ size_t pos;
+ if (direction == CURSOR_RIGHT) {
+ pos = std::min(selection.caret_pos() + 1, text().length());
+ while (iter.Advance()) {
+ pos = iter.pos();
+ if (iter.IsWord() && pos > selection.caret_pos())
+ break;
+ }
+ } else { // direction == CURSOR_LEFT
+ // Notes: We always iterate words from the beginning.
+ // This is probably fast enough for our usage, but we may
+ // want to modify WordIterator so that it can start from the
+ // middle of string and advance backwards.
+ pos = std::max<int>(selection.caret_pos() - 1, 0);
+ while (iter.Advance()) {
+ if (iter.IsWord()) {
+ size_t begin = iter.pos() - iter.GetString().length();
+ if (begin == selection.caret_pos()) {
+ // The cursor is at the beginning of a word.
+ // Move to previous word.
+ break;
+ } else if (iter.pos() >= selection.caret_pos()) {
+ // The cursor is in the middle or at the end of a word.
+ // Move to the top of current word.
+ pos = begin;
+ break;
+ }
+ pos = iter.pos() - iter.GetString().length();
+ }
+ }
+ }
+ return SelectionModel(pos, CURSOR_FORWARD);
+}
+
+Range RenderTextHarfBuzz::GetGlyphBounds(size_t index) {
+ const size_t run_index =
+ GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD));
+ // Return edge bounds if the index is invalid or beyond the layout text size.
+ if (run_index >= runs_.size())
+ return Range(GetStringSize().width());
+ const size_t layout_index = TextIndexToLayoutIndex(index);
+ return Range(runs_[run_index]->GetGlyphXBoundary(layout_index, false),
+ runs_[run_index]->GetGlyphXBoundary(layout_index, true));
+}
+
+std::vector<Rect> RenderTextHarfBuzz::GetSubstringBounds(const Range& range) {
+ DCHECK(!needs_layout_);
+ DCHECK(Range(0, text().length()).Contains(range));
+ Range layout_range(TextIndexToLayoutIndex(range.start()),
+ TextIndexToLayoutIndex(range.end()));
+ DCHECK(Range(0, GetLayoutText().length()).Contains(layout_range));
+
+ std::vector<Rect> rects;
+ if (layout_range.is_empty())
+ return rects;
+ std::vector<Range> bounds;
+
+ // Add a Range for each run/selection intersection.
+ // TODO(msw): The bounds should probably not always be leading the range ends.
+ for (size_t i = 0; i < runs_.size(); ++i) {
+ const internal::TextRunHarfBuzz* run = runs_[visual_to_logical_[i]];
+ Range intersection = run->range.Intersect(layout_range);
+ if (intersection.IsValid()) {
+ DCHECK(!intersection.is_reversed());
+ Range range_x(run->GetGlyphXBoundary(intersection.start(), false),
+ run->GetGlyphXBoundary(intersection.end(), false));
+ if (range_x.is_empty())
+ continue;
+ range_x = Range(range_x.GetMin(), range_x.GetMax());
+ // Union this with the last range if they're adjacent.
+ DCHECK(bounds.empty() || bounds.back().GetMax() <= range_x.GetMin());
+ if (!bounds.empty() && bounds.back().GetMax() == range_x.GetMin()) {
+ range_x = Range(bounds.back().GetMin(), range_x.GetMax());
+ bounds.pop_back();
+ }
+ bounds.push_back(range_x);
+ }
+ }
+ for (size_t i = 0; i < bounds.size(); ++i) {
+ std::vector<Rect> current_rects = TextBoundsToViewBounds(bounds[i]);
+ rects.insert(rects.end(), current_rects.begin(), current_rects.end());
+ }
+ return rects;
+}
+
+size_t RenderTextHarfBuzz::TextIndexToLayoutIndex(size_t index) const {
+ DCHECK_LE(index, text().length());
+ ptrdiff_t i = obscured() ? UTF16IndexToOffset(text(), 0, index) : index;
+ CHECK_GE(i, 0);
+ // Clamp layout indices to the length of the text actually used for layout.
+ return std::min<size_t>(GetLayoutText().length(), i);
+}
+
+size_t RenderTextHarfBuzz::LayoutIndexToTextIndex(size_t index) const {
+ if (!obscured())
+ return index;
+
+ DCHECK_LE(index, GetLayoutText().length());
+ const size_t text_index = UTF16OffsetToIndex(text(), 0, index);
+ DCHECK_LE(text_index, text().length());
+ return text_index;
+}
+
+bool RenderTextHarfBuzz::IsValidCursorIndex(size_t index) {
+ if (index == 0 || index == text().length())
+ return true;
+ if (!IsValidLogicalIndex(index))
+ return false;
+ EnsureLayout();
+ // Disallow indices amid multi-character graphemes by checking glyph bounds.
+ // These characters are not surrogate-pairs, but may yield a single glyph:
+ // \x0915\x093f - (ki) - one of many Devanagari biconsonantal conjuncts.
+ // \x0e08\x0e33 - (cho chan + sara am) - a Thai consonant and vowel pair.
+ return GetGlyphBounds(index) != GetGlyphBounds(index - 1);
+}
+
+void RenderTextHarfBuzz::ResetLayout() {
+ needs_layout_ = true;
+}
+
+void RenderTextHarfBuzz::EnsureLayout() {
+ if (needs_layout_) {
+ runs_.clear();
+
+ if (!GetLayoutText().empty()) {
+ ItemizeText();
+
+ for (size_t i = 0; i < runs_.size(); ++i)
+ ShapeRun(runs_[i]);
+
+ // Precalculate run width information.
+ size_t preceding_run_widths = 0;
+ for (size_t i = 0; i < runs_.size(); ++i) {
+ internal::TextRunHarfBuzz* run = runs_[visual_to_logical_[i]];
+ run->preceding_run_widths = preceding_run_widths;
+ preceding_run_widths += run->width;
+ }
+ }
+
+ needs_layout_ = false;
+ std::vector<internal::Line> empty_lines;
+ set_lines(&empty_lines);
+ }
+
+ if (lines().empty()) {
+ std::vector<internal::Line> lines;
+ lines.push_back(internal::Line());
+ lines[0].baseline = font_list().GetBaseline();
+ lines[0].size.set_height(font_list().GetHeight());
+
+ int current_x = 0;
+ SkPaint paint;
+
+ for (size_t i = 0; i < runs_.size(); ++i) {
+ const internal::TextRunHarfBuzz& run = *runs_[visual_to_logical_[i]];
+ internal::LineSegment segment;
+ segment.x_range = Range(current_x, current_x + run.width);
+ segment.char_range = run.range;
+ segment.run = i;
+ lines[0].segments.push_back(segment);
+
+ paint.setTypeface(run.skia_face.get());
+ paint.setTextSize(run.font_size);
+ SkPaint::FontMetrics metrics;
+ paint.getFontMetrics(&metrics);
+
+ lines[0].size.set_width(lines[0].size.width() + run.width);
+ lines[0].size.set_height(std::max(lines[0].size.height(),
+ SkScalarRoundToInt(metrics.fDescent - metrics.fAscent)));
+ lines[0].baseline = std::max(lines[0].baseline,
+ SkScalarRoundToInt(-metrics.fAscent));
+ }
+
+ set_lines(&lines);
+ }
+}
+
+void RenderTextHarfBuzz::DrawVisualText(Canvas* canvas) {
+ DCHECK(!needs_layout_);
+
+ int current_x = 0;
+
+ internal::SkiaTextRenderer renderer(canvas);
+ ApplyFadeEffects(&renderer);
+ ApplyTextShadows(&renderer);
+
+#if defined(OS_WIN)
+ bool smoothing_enabled;
+ bool cleartype_enabled;
+ GetCachedFontSmoothingSettings(&smoothing_enabled, &cleartype_enabled);
+ // Note that |cleartype_enabled| corresponds to Skia's |enable_lcd_text|.
+ renderer.SetFontSmoothingSettings(
+ smoothing_enabled, cleartype_enabled && !background_is_transparent(),
+ smoothing_enabled /* subpixel_positioning */);
+#endif
+
+ ApplyCompositionAndSelectionStyles();
+
+ const Vector2d line_offset = GetLineOffset(0);
+
+ for (size_t i = 0; i < runs_.size(); ++i) {
+ const internal::TextRunHarfBuzz& run = *runs_[visual_to_logical_[i]];
+ renderer.SetTypeface(run.skia_face.get());
+ renderer.SetTextSize(run.font_size);
+
+ canvas->Save();
+ Vector2d origin = line_offset + Vector2d(current_x, lines()[0].baseline);
+ canvas->Translate(origin);
+
+ for (BreakList<SkColor>::const_iterator it =
+ colors().GetBreak(run.range.start());
+ it != colors().breaks().end() && it->first < run.range.end();
+ ++it) {
+ const Range intersection = colors().GetRange(it).Intersect(run.range);
+ const Range colored_glyphs = run.CharRangeToGlyphRange(intersection);
+ // The range may be empty if a portion of a multi-character grapheme is
+ // selected, yielding two colors for a single glyph. For now, this just
+ // paints the glyph with a single style, but it should paint it twice,
+ // clipped according to selection bounds. See http://crbug.com/366786
+ if (colored_glyphs.is_empty())
+ continue;
+
+ renderer.SetForegroundColor(it->second);
+ renderer.DrawPosText(&run.positions[colored_glyphs.start()],
+ &run.glyphs[colored_glyphs.start()],
+ colored_glyphs.length());
+ int width = (colored_glyphs.end() == run.glyph_count ? run.width :
+ run.positions[colored_glyphs.end()].x()) -
+ run.positions[colored_glyphs.start()].x();
+ renderer.DrawDecorations(0, 0, width, run.underline, run.strike,
+ run.diagonal_strike);
+ }
+
+ canvas->Restore();
+ current_x += run.width;
+ }
+
+ renderer.EndDiagonalStrike();
+
+ UndoCompositionAndSelectionStyles();
+}
+
+size_t RenderTextHarfBuzz::GetRunContainingCaret(
+ const SelectionModel& caret) const {
+ DCHECK(!needs_layout_);
+ size_t layout_position = TextIndexToLayoutIndex(caret.caret_pos());
+ LogicalCursorDirection affinity = caret.caret_affinity();
+ for (size_t run = 0; run < runs_.size(); ++run) {
+ if (RangeContainsCaret(runs_[run]->range, layout_position, affinity))
+ return run;
+ }
+ return runs_.size();
+}
+
+size_t RenderTextHarfBuzz::GetRunContainingXCoord(int x, int* offset) const {
+ DCHECK(!needs_layout_);
+ if (x < 0)
+ return runs_.size();
+ // Find the text run containing the argument point (assumed already offset).
+ int current_x = 0;
+ for (size_t i = 0; i < runs_.size(); ++i) {
+ size_t run = visual_to_logical_[i];
+ current_x += runs_[run]->width;
+ if (x < current_x) {
+ *offset = x - (current_x - runs_[run]->width);
+ return run;
+ }
+ }
+ return runs_.size();
+}
+
+SelectionModel RenderTextHarfBuzz::FirstSelectionModelInsideRun(
+ const internal::TextRunHarfBuzz* run) {
+ size_t position = LayoutIndexToTextIndex(run->range.start());
+ position = IndexOfAdjacentGrapheme(position, CURSOR_FORWARD);
+ return SelectionModel(position, CURSOR_BACKWARD);
+}
+
+SelectionModel RenderTextHarfBuzz::LastSelectionModelInsideRun(
+ const internal::TextRunHarfBuzz* run) {
+ size_t position = LayoutIndexToTextIndex(run->range.end());
+ position = IndexOfAdjacentGrapheme(position, CURSOR_BACKWARD);
+ return SelectionModel(position, CURSOR_FORWARD);
+}
+
+void RenderTextHarfBuzz::ItemizeText() {
+ const base::string16& text = GetLayoutText();
+ const bool is_text_rtl = GetTextDirection() == base::i18n::RIGHT_TO_LEFT;
+ DCHECK_NE(0U, text.length());
+
+ // If ICU fails to itemize the text, we create a run that spans the entire
+ // text. This is needed because leaving the runs set empty causes some clients
+ // to misbehave since they expect non-zero text metrics from a non-empty text.
+ base::i18n::BiDiLineIterator bidi_iterator;
+ if (!bidi_iterator.Open(text, is_text_rtl, false)) {
+ internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz;
+ run->range = Range(0, text.length());
+ runs_.push_back(run);
+ visual_to_logical_ = logical_to_visual_ = std::vector<int32_t>(1, 0);
+ return;
+ }
+
+ // Temporarily apply composition underlines and selection colors.
+ ApplyCompositionAndSelectionStyles();
+
+ // Build the list of runs from the script items and ranged styles. Use an
+ // empty color BreakList to avoid breaking runs at color boundaries.
+ BreakList<SkColor> empty_colors;
+ empty_colors.SetMax(text.length());
+ internal::StyleIterator style(empty_colors, styles());
+
+ for (size_t run_break = 0; run_break < text.length();) {
+ internal::TextRunHarfBuzz* run = new internal::TextRunHarfBuzz;
+ run->range.set_start(run_break);
+ run->font_style = (style.style(BOLD) ? Font::BOLD : 0) |
+ (style.style(ITALIC) ? Font::ITALIC : 0);
+ run->strike = style.style(STRIKE);
+ run->diagonal_strike = style.style(DIAGONAL_STRIKE);
+ run->underline = style.style(UNDERLINE);
+
+ int32 script_item_break = 0;
+ bidi_iterator.GetLogicalRun(run_break, &script_item_break, &run->level);
+ // Odd BiDi embedding levels correspond to RTL runs.
+ run->is_rtl = (run->level % 2) == 1;
+ // Find the length and script of this script run.
+ script_item_break = ScriptInterval(text, run_break,
+ script_item_break - run_break, &run->script) + run_break;
+
+ // Find the next break and advance the iterators as needed.
+ run_break = std::min(static_cast<size_t>(script_item_break),
+ TextIndexToLayoutIndex(style.GetRange().end()));
+
+ // Break runs adjacent to character substrings in certain code blocks.
+ // This avoids using their fallback fonts for more characters than needed,
+ // in cases like "\x25B6 Media Title", etc. http://crbug.com/278913
+ if (run_break > run->range.start())
+ run_break = FindUnusualCharacter(text, run->range.start(), run_break);
+
+ DCHECK(IsValidCodePointIndex(text, run_break));
+ style.UpdatePosition(LayoutIndexToTextIndex(run_break));
+ run->range.set_end(run_break);
+
+ runs_.push_back(run);
+ }
+
+ // Undo the temporarily applied composition underlines and selection colors.
+ UndoCompositionAndSelectionStyles();
+
+ const size_t num_runs = runs_.size();
+ std::vector<UBiDiLevel> levels(num_runs);
+ for (size_t i = 0; i < num_runs; ++i)
+ levels[i] = runs_[i]->level;
+ visual_to_logical_.resize(num_runs);
+ ubidi_reorderVisual(&levels[0], num_runs, &visual_to_logical_[0]);
+ logical_to_visual_.resize(num_runs);
+ ubidi_reorderLogical(&levels[0], num_runs, &logical_to_visual_[0]);
+}
+
+void RenderTextHarfBuzz::ShapeRun(internal::TextRunHarfBuzz* run) {
+ const base::string16& text = GetLayoutText();
+ // TODO(ckocagil|yukishiino): Implement font fallback.
+ const Font& primary_font = font_list().GetPrimaryFont();
+ run->skia_face = internal::CreateSkiaTypeface(primary_font.GetFontName(),
+ run->font_style);
+ run->font_size = primary_font.GetFontSize();
+
+ hb_font_t* harfbuzz_font = CreateHarfBuzzFont(run->skia_face.get(),
+ run->font_size);
+
+ // Create a HarfBuzz buffer and add the string to be shaped. The HarfBuzz
+ // buffer holds our text, run information to be used by the shaping engine,
+ // and the resulting glyph data.
+ hb_buffer_t* buffer = hb_buffer_create();
+ hb_buffer_add_utf16(buffer, reinterpret_cast<const uint16*>(text.c_str()),
+ text.length(), run->range.start(), run->range.length());
+ hb_buffer_set_script(buffer, ICUScriptToHBScript(run->script));
+ hb_buffer_set_direction(buffer,
+ run->is_rtl ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
+ // TODO(ckocagil): Should we determine the actual language?
+ hb_buffer_set_language(buffer, hb_language_get_default());
+
+ // Shape the text.
+ hb_shape(harfbuzz_font, buffer, NULL, 0);
+
+ // Populate the run fields with the resulting glyph data in the buffer.
+ unsigned int glyph_count = 0;
+ hb_glyph_info_t* infos = hb_buffer_get_glyph_infos(buffer, &glyph_count);
+ hb_glyph_position_t* hb_positions = hb_buffer_get_glyph_positions(buffer,
+ NULL);
+ run->glyph_count = glyph_count;
+ run->glyphs.reset(new uint16[run->glyph_count]);
+ run->glyph_to_char.reset(new uint32[run->glyph_count]);
+ run->positions.reset(new SkPoint[run->glyph_count]);
+ for (size_t i = 0; i < run->glyph_count; ++i) {
+ run->glyphs[i] = infos[i].codepoint;
+ run->glyph_to_char[i] = infos[i].cluster;
+ const int x_offset =
+ SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_offset));
+ const int y_offset =
+ SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].y_offset));
+ run->positions[i].set(run->width + x_offset, y_offset);
+ run->width +=
+ SkScalarRoundToInt(SkFixedToScalar(hb_positions[i].x_advance));
+ }
+
+ hb_buffer_destroy(buffer);
+ hb_font_destroy(harfbuzz_font);
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/render_text_harfbuzz.h b/chromium/ui/gfx/render_text_harfbuzz.h
new file mode 100644
index 00000000000..59ce92f21c3
--- /dev/null
+++ b/chromium/ui/gfx/render_text_harfbuzz.h
@@ -0,0 +1,130 @@
+// 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_RENDER_TEXT_HARFBUZZ_H_
+#define UI_GFX_RENDER_TEXT_HARFBUZZ_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "third_party/harfbuzz-ng/src/hb.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"
+
+namespace gfx {
+
+namespace internal {
+
+struct GFX_EXPORT TextRunHarfBuzz {
+ TextRunHarfBuzz();
+ ~TextRunHarfBuzz();
+
+ // Returns the index of the first glyph that corresponds to the character at
+ // |pos|.
+ size_t CharToGlyph(size_t pos) const;
+
+ // Returns the corresponding glyph range of the given character range.
+ // |range| is in text-space (0 corresponds to |GetLayoutText()[0]|). Returned
+ // value is in run-space (0 corresponds to the first glyph in the run).
+ Range CharRangeToGlyphRange(const Range& range) const;
+
+ // Returns whether the given shaped run contains any missing glyphs.
+ bool HasMissingGlyphs() const;
+
+ // Returns the X coordinate of the leading or |trailing| edge of the glyph
+ // starting at |text_index|, relative to the left of the text (not the view).
+ int GetGlyphXBoundary(size_t text_index, bool trailing) const;
+
+ int width;
+ int preceding_run_widths;
+ Range range;
+ bool is_rtl;
+ UBiDiLevel level;
+ UScriptCode script;
+
+ scoped_ptr<uint16[]> glyphs;
+ scoped_ptr<SkPoint[]> positions;
+ scoped_ptr<uint32[]> glyph_to_char;
+ size_t glyph_count;
+
+ skia::RefPtr<SkTypeface> skia_face;
+ int font_size;
+ int font_style;
+ bool strike;
+ bool diagonal_strike;
+ bool underline;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextRunHarfBuzz);
+};
+
+} // namespace internal
+
+class GFX_EXPORT RenderTextHarfBuzz : public RenderText {
+ public:
+ RenderTextHarfBuzz();
+ virtual ~RenderTextHarfBuzz();
+
+ // Overridden from RenderText.
+ virtual Size GetStringSize() OVERRIDE;
+ virtual SelectionModel FindCursorPosition(const Point& point) OVERRIDE;
+ virtual std::vector<FontSpan> GetFontSpansForTesting() OVERRIDE;
+
+ protected:
+ // Overridden from RenderText.
+ virtual int GetLayoutTextBaseline() OVERRIDE;
+ virtual SelectionModel AdjacentCharSelectionModel(
+ const SelectionModel& selection,
+ VisualCursorDirection direction) OVERRIDE;
+ virtual SelectionModel AdjacentWordSelectionModel(
+ const SelectionModel& selection,
+ VisualCursorDirection direction) OVERRIDE;
+ virtual Range GetGlyphBounds(size_t index) OVERRIDE;
+ virtual std::vector<Rect> GetSubstringBounds(const Range& range) OVERRIDE;
+ virtual size_t TextIndexToLayoutIndex(size_t index) const OVERRIDE;
+ virtual size_t LayoutIndexToTextIndex(size_t index) const OVERRIDE;
+ virtual bool IsValidCursorIndex(size_t index) OVERRIDE;
+ virtual void ResetLayout() OVERRIDE;
+ virtual void EnsureLayout() OVERRIDE;
+ virtual void DrawVisualText(Canvas* canvas) OVERRIDE;
+
+ private:
+ friend class RenderTextTest;
+ FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_RunDirection);
+ FRIEND_TEST_ALL_PREFIXES(RenderTextTest, HarfBuzz_BreakRunsByUnicodeBlocks);
+
+ // Return the run index that contains the argument; or the length of the
+ // |runs_| vector if argument exceeds the text length or width.
+ size_t GetRunContainingCaret(const SelectionModel& caret) const;
+ size_t GetRunContainingXCoord(int x, int* offset) const;
+
+ // Given a |run|, returns the SelectionModel that contains the logical first
+ // or last caret position inside (not at a boundary of) the run.
+ // The returned value represents a cursor/caret position without a selection.
+ SelectionModel FirstSelectionModelInsideRun(
+ const internal::TextRunHarfBuzz* run);
+ SelectionModel LastSelectionModelInsideRun(
+ const internal::TextRunHarfBuzz* run);
+
+ // Break the text into logical runs and populate the visual <-> logical maps.
+ void ItemizeText();
+
+ // Shape the glyphs needed for the text |run|.
+ void ShapeRun(internal::TextRunHarfBuzz* run);
+
+ // Text runs in logical order.
+ ScopedVector<internal::TextRunHarfBuzz> runs_;
+
+ // Maps visual run indices to logical run indices and vice versa.
+ std::vector<int32_t> visual_to_logical_;
+ std::vector<int32_t> logical_to_visual_;
+
+ bool needs_layout_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderTextHarfBuzz);
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_RENDER_TEXT_HARFBUZZ_H_
diff --git a/chromium/ui/gfx/render_text_mac.cc b/chromium/ui/gfx/render_text_mac.cc
index 4feb9302c18..68780f84b94 100644
--- a/chromium/ui/gfx/render_text_mac.cc
+++ b/chromium/ui/gfx/render_text_mac.cc
@@ -45,7 +45,7 @@ std::vector<RenderText::FontSpan> RenderTextMac::GetFontSpansForTesting() {
std::vector<RenderText::FontSpan> spans;
for (size_t i = 0; i < runs_.size(); ++i) {
- gfx::Font font(runs_[i].font_name, runs_[i].text_size);
+ Font font(runs_[i].font_name, runs_[i].text_size);
const CFRange cf_range = CTRunGetStringRange(runs_[i].ct_run);
const Range range(cf_range.location, cf_range.location + cf_range.length);
spans.push_back(RenderText::FontSpan(font, range));
@@ -93,9 +93,9 @@ size_t RenderTextMac::LayoutIndexToTextIndex(size_t index) const {
return index;
}
-bool RenderTextMac::IsCursorablePosition(size_t position) {
+bool RenderTextMac::IsValidCursorIndex(size_t index) {
// TODO(asvitkine): Implement this. http://crbug.com/131618
- return true;
+ return IsValidLogicalIndex(index);
}
void RenderTextMac::ResetLayout() {
@@ -111,8 +111,8 @@ void RenderTextMac::EnsureLayout() {
runs_.clear();
runs_valid_ = false;
- const Font& font = GetPrimaryFont();
- CTFontRef ct_font = base::mac::NSToCFCast(font.GetNativeFont());
+ CTFontRef ct_font = base::mac::NSToCFCast(
+ font_list().GetPrimaryFont().GetNativeFont());
const void* keys[] = { kCTFontAttributeName };
const void* values[] = { ct_font };
@@ -174,6 +174,8 @@ void RenderTextMac::DrawVisualText(Canvas* canvas) {
renderer.DrawDecorations(run.origin.x(), run.origin.y(), run.width,
run.underline, run.strike, run.diagonal_strike);
}
+
+ renderer.EndDiagonalStrike();
}
RenderTextMac::TextRun::TextRun()
@@ -209,7 +211,7 @@ void RenderTextMac::ApplyStyles(CFMutableAttributedStringRef attr_string,
end = TextIndexToLayoutIndex(style.GetRange().end());
const CFRange range = CFRangeMake(i, end - i);
base::ScopedCFTypeRef<CGColorRef> foreground(
- gfx::CGColorCreateFromSkColor(style.color()));
+ CGColorCreateFromSkColor(style.color()));
CFAttributedStringSetAttribute(attr_string, range,
kCTForegroundColorAttributeName, foreground);
CFArrayAppendValue(attributes_, foreground);
@@ -252,9 +254,9 @@ void RenderTextMac::ComputeRuns() {
// TODO(asvitkine): Don't use GetLineOffset() until draw time, since it may be
// updated based on alignment changes without resetting the layout.
- gfx::Vector2d text_offset = GetLineOffset(0);
+ Vector2d text_offset = GetLineOffset(0);
// Skia will draw glyphs with respect to the baseline.
- text_offset += gfx::Vector2d(0, common_baseline_);
+ text_offset += Vector2d(0, common_baseline_);
const SkScalar x = SkIntToScalar(text_offset.x());
const SkScalar y = SkIntToScalar(text_offset.y());
@@ -323,7 +325,7 @@ void RenderTextMac::ComputeRuns() {
base::mac::GetValueFromDictionary<CGColorRef>(
attributes, kCTForegroundColorAttributeName);
if (foreground)
- run->foreground = gfx::CGColorRefToSkColor(foreground);
+ run->foreground = CGColorRefToSkColor(foreground);
const CFNumberRef underline =
base::mac::GetValueFromDictionary<CFNumberRef>(
@@ -337,7 +339,7 @@ void RenderTextMac::ComputeRuns() {
runs_valid_ = true;
}
-RenderText* RenderText::CreateInstance() {
+RenderText* RenderText::CreateNativeInstance() {
return new RenderTextMac;
}
diff --git a/chromium/ui/gfx/render_text_mac.h b/chromium/ui/gfx/render_text_mac.h
index 3a18a0fad45..ad03b845935 100644
--- a/chromium/ui/gfx/render_text_mac.h
+++ b/chromium/ui/gfx/render_text_mac.h
@@ -44,7 +44,7 @@ class RenderTextMac : public RenderText {
virtual std::vector<Rect> GetSubstringBounds(const Range& range) OVERRIDE;
virtual size_t TextIndexToLayoutIndex(size_t index) const OVERRIDE;
virtual size_t LayoutIndexToTextIndex(size_t index) const OVERRIDE;
- virtual bool IsCursorablePosition(size_t position) OVERRIDE;
+ virtual bool IsValidCursorIndex(size_t index) OVERRIDE;
virtual void ResetLayout() OVERRIDE;
virtual void EnsureLayout() OVERRIDE;
virtual void DrawVisualText(Canvas* canvas) OVERRIDE;
diff --git a/chromium/ui/gfx/render_text_ozone.cc b/chromium/ui/gfx/render_text_ozone.cc
index 058b5a6389d..fb5ef993d8b 100644
--- a/chromium/ui/gfx/render_text_ozone.cc
+++ b/chromium/ui/gfx/render_text_ozone.cc
@@ -6,7 +6,7 @@
namespace gfx {
-RenderText* RenderText::CreateInstance() {
+RenderText* RenderText::CreateNativeInstance() {
return NULL;
}
diff --git a/chromium/ui/gfx/render_text_pango.cc b/chromium/ui/gfx/render_text_pango.cc
index f120a5c10bb..a1269264617 100644
--- a/chromium/ui/gfx/render_text_pango.cc
+++ b/chromium/ui/gfx/render_text_pango.cc
@@ -40,8 +40,7 @@ bool IsForwardMotion(VisualCursorDirection direction, const PangoItem* item) {
}
// Checks whether |range| contains |index|. This is not the same as calling
-// |range.Contains(gfx::Range(index))| - as that would return true when
-// |index| == |range.end()|.
+// range.Contains(Range(index)), which returns true if |index| == |range.end()|.
bool IndexInRange(const Range& range, size_t index) {
return index >= range.start() && index < range.end();
}
@@ -211,6 +210,7 @@ SelectionModel RenderTextPango::AdjacentWordSelectionModel(
}
Range RenderTextPango::GetGlyphBounds(size_t index) {
+ EnsureLayout();
PangoRectangle pos;
pango_layout_index_to_pos(layout_, TextIndexToLayoutIndex(index), &pos);
// TODO(derat): Support fractional ranges for subpixel positioning?
@@ -248,7 +248,7 @@ std::vector<Rect> RenderTextPango::GetSubstringBounds(const Range& range) {
size_t RenderTextPango::TextIndexToLayoutIndex(size_t index) const {
DCHECK(layout_);
- ptrdiff_t offset = gfx::UTF16IndexToOffset(text(), 0, index);
+ ptrdiff_t offset = UTF16IndexToOffset(text(), 0, index);
// Clamp layout indices to the length of the text actually used for layout.
offset = std::min<size_t>(offset, g_utf8_strlen(layout_text_, -1));
const char* layout_pointer = g_utf8_offset_to_pointer(layout_text_, offset);
@@ -259,24 +259,19 @@ size_t RenderTextPango::LayoutIndexToTextIndex(size_t index) const {
DCHECK(layout_);
const char* layout_pointer = layout_text_ + index;
const long offset = g_utf8_pointer_to_offset(layout_text_, layout_pointer);
- return gfx::UTF16OffsetToIndex(text(), 0, offset);
+ return UTF16OffsetToIndex(text(), 0, offset);
}
-bool RenderTextPango::IsCursorablePosition(size_t position) {
- if (position == 0 && text().empty())
+bool RenderTextPango::IsValidCursorIndex(size_t index) {
+ if (index == 0 || index == text().length())
return true;
- if (position >= text().length())
- return position == text().length();
- if (!gfx::IsValidCodePointIndex(text(), position))
+ if (!IsValidLogicalIndex(index))
return false;
EnsureLayout();
- ptrdiff_t offset = gfx::UTF16IndexToOffset(text(), 0, position);
- // Check that the index corresponds with a valid text code point, that it is
- // marked as a legitimate cursor position by Pango, and that it is not
- // truncated from layout text (its glyph is shown on screen).
- return (offset < num_log_attrs_ && log_attrs_[offset].is_cursor_position &&
- offset < g_utf8_strlen(layout_text_, -1));
+ ptrdiff_t offset = UTF16IndexToOffset(text(), 0, index);
+ // Check that the index is marked as a legitimate cursor position by Pango.
+ return offset < num_log_attrs_ && log_attrs_[offset].is_cursor_position;
}
void RenderTextPango::ResetLayout() {
@@ -353,7 +348,7 @@ void RenderTextPango::SetupPangoAttributes(PangoLayout* layout) {
const size_t italic_end = styles()[ITALIC].GetRange(italic).end();
const size_t style_end = std::min(bold_end, italic_end);
if (style != font_list().GetFontStyle()) {
- FontList derived_font_list = font_list().DeriveFontList(style);
+ FontList derived_font_list = font_list().DeriveWithStyle(style);
ScopedPangoFontDescription desc(pango_font_description_from_string(
derived_font_list.GetFontDescriptionString().c_str()));
@@ -390,14 +385,31 @@ void RenderTextPango::DrawVisualText(Canvas* canvas) {
ApplyTextShadows(&renderer);
// TODO(derat): Use font-specific params: http://crbug.com/125235
- const gfx::FontRenderParams& render_params =
- gfx::GetDefaultFontRenderParams();
+ const FontRenderParams& render_params = GetDefaultFontRenderParams();
const bool use_subpixel_rendering =
render_params.subpixel_rendering !=
- gfx::FontRenderParams::SUBPIXEL_RENDERING_NONE;
+ FontRenderParams::SUBPIXEL_RENDERING_NONE;
renderer.SetFontSmoothingSettings(
render_params.antialiasing,
- use_subpixel_rendering && !background_is_transparent());
+ use_subpixel_rendering && !background_is_transparent(),
+ render_params.subpixel_positioning);
+
+ SkPaint::Hinting skia_hinting = SkPaint::kNormal_Hinting;
+ switch (render_params.hinting) {
+ case FontRenderParams::HINTING_NONE:
+ skia_hinting = SkPaint::kNo_Hinting;
+ break;
+ case FontRenderParams::HINTING_SLIGHT:
+ skia_hinting = SkPaint::kSlight_Hinting;
+ break;
+ case FontRenderParams::HINTING_MEDIUM:
+ skia_hinting = SkPaint::kNormal_Hinting;
+ break;
+ case FontRenderParams::HINTING_FULL:
+ skia_hinting = SkPaint::kFull_Hinting;
+ break;
+ }
+ renderer.SetFontHinting(skia_hinting);
// Temporarily apply composition underlines and selection colors.
ApplyCompositionAndSelectionStyles();
@@ -468,6 +480,8 @@ void RenderTextPango::DrawVisualText(Canvas* canvas) {
} while (glyph_index < glyph_count);
}
+ renderer.EndDiagonalStrike();
+
// Undo the temporarily applied composition underlines and selection colors.
UndoCompositionAndSelectionStyles();
}
@@ -507,7 +521,7 @@ size_t RenderTextPango::GetGlyphTextIndex(PangoLayoutRun* run,
run->glyphs->log_clusters[glyph_index]);
}
-RenderText* RenderText::CreateInstance() {
+RenderText* RenderText::CreateNativeInstance() {
return new RenderTextPango;
}
diff --git a/chromium/ui/gfx/render_text_pango.h b/chromium/ui/gfx/render_text_pango.h
index ba7361c4d30..4c62e0aab89 100644
--- a/chromium/ui/gfx/render_text_pango.h
+++ b/chromium/ui/gfx/render_text_pango.h
@@ -36,7 +36,7 @@ class RenderTextPango : public RenderText {
virtual std::vector<Rect> GetSubstringBounds(const Range& range) OVERRIDE;
virtual size_t TextIndexToLayoutIndex(size_t index) const OVERRIDE;
virtual size_t LayoutIndexToTextIndex(size_t index) const OVERRIDE;
- virtual bool IsCursorablePosition(size_t position) OVERRIDE;
+ virtual bool IsValidCursorIndex(size_t index) OVERRIDE;
virtual void ResetLayout() OVERRIDE;
virtual void EnsureLayout() OVERRIDE;
virtual void DrawVisualText(Canvas* canvas) OVERRIDE;
diff --git a/chromium/ui/gfx/render_text_unittest.cc b/chromium/ui/gfx/render_text_unittest.cc
index c8c50d42814..4686066f088 100644
--- a/chromium/ui/gfx/render_text_unittest.cc
+++ b/chromium/ui/gfx/render_text_unittest.cc
@@ -14,6 +14,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/break_list.h"
#include "ui/gfx/canvas.h"
+#include "ui/gfx/render_text_harfbuzz.h"
#if defined(OS_WIN)
#include "base/win/windows_version.h"
@@ -24,9 +25,9 @@
#include "ui/gfx/render_text_pango.h"
#endif
-#if defined(TOOLKIT_GTK)
-#include <gtk/gtk.h>
-#endif
+using base::ASCIIToUTF16;
+using base::UTF8ToUTF16;
+using base::WideToUTF16;
namespace gfx {
@@ -44,8 +45,7 @@ const wchar_t kRtlLtrRtl[] = L"\x5d0" L"a" L"\x5d1";
#endif
// Checks whether |range| contains |index|. This is not the same as calling
-// |range.Contains(gfx::Range(index))| - as that would return true when
-// |index| == |range.end()|.
+// range.Contains(Range(index)), which returns true if |index| == |range.end()|.
bool IndexInRange(const Range& range, size_t index) {
return index >= range.start() && index < range.end();
}
@@ -59,10 +59,6 @@ base::string16 GetSelectedText(RenderText* render_text) {
void SetRTL(bool rtl) {
// Override the current locale/direction.
base::i18n::SetICUDefaultLocale(rtl ? "he" : "en");
-#if defined(TOOLKIT_GTK)
- // Do the same for GTK, which does not rely on the ICU default locale.
- gtk_widget_set_default_direction(rtl ? GTK_TEXT_DIR_RTL : GTK_TEXT_DIR_LTR);
-#endif
EXPECT_EQ(rtl, base::i18n::IsRTL());
}
@@ -283,10 +279,10 @@ TEST_F(RenderTextTest, ObscuredText) {
render_text->SetObscured(true);
// Surrogate pairs are counted as one code point.
- const char16 invalid_surrogates[] = {0xDC00, 0xD800, 0};
+ const base::char16 invalid_surrogates[] = {0xDC00, 0xD800, 0};
render_text->SetText(invalid_surrogates);
EXPECT_EQ(ASCIIToUTF16("**"), render_text->GetLayoutText());
- const char16 valid_surrogates[] = {0xD800, 0xDC00, 0};
+ const base::char16 valid_surrogates[] = {0xD800, 0xDC00, 0};
render_text->SetText(valid_surrogates);
EXPECT_EQ(ASCIIToUTF16("*"), render_text->GetLayoutText());
EXPECT_EQ(0U, render_text->cursor_position());
@@ -299,9 +295,9 @@ TEST_F(RenderTextTest, ObscuredText) {
EXPECT_EQ(1U, render_text->TextIndexToLayoutIndex(2U));
EXPECT_EQ(0U, render_text->LayoutIndexToTextIndex(0U));
EXPECT_EQ(2U, render_text->LayoutIndexToTextIndex(1U));
- EXPECT_TRUE(render_text->IsCursorablePosition(0U));
- EXPECT_FALSE(render_text->IsCursorablePosition(1U));
- EXPECT_TRUE(render_text->IsCursorablePosition(2U));
+ EXPECT_TRUE(render_text->IsValidCursorIndex(0U));
+ EXPECT_FALSE(render_text->IsValidCursorIndex(1U));
+ EXPECT_TRUE(render_text->IsValidCursorIndex(2U));
// FindCursorPosition() should not return positions between a surrogate pair.
render_text->SetDisplayRect(Rect(0, 0, 20, 20));
@@ -370,37 +366,127 @@ TEST_F(RenderTextTest, RevealObscuredText) {
EXPECT_EQ(ASCIIToUTF16("**********"), render_text->GetLayoutText());
// Text with invalid surrogates.
- const char16 invalid_surrogates[] = {0xDC00, 0xD800, 'h', 'o', 'p', 0};
+ const base::char16 invalid_surrogates[] = {0xDC00, 0xD800, 'h', 'o', 'p', 0};
render_text->SetText(invalid_surrogates);
EXPECT_EQ(ASCIIToUTF16("*****"), render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(0);
- const char16 invalid_expect_0[] = {0xDC00, '*', '*', '*', '*', 0};
+ const base::char16 invalid_expect_0[] = {0xDC00, '*', '*', '*', '*', 0};
EXPECT_EQ(invalid_expect_0, render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(1);
- const char16 invalid_expect_1[] = {'*', 0xD800, '*', '*', '*', 0};
+ const base::char16 invalid_expect_1[] = {'*', 0xD800, '*', '*', '*', 0};
EXPECT_EQ(invalid_expect_1, render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(2);
EXPECT_EQ(ASCIIToUTF16("**h**"), render_text->GetLayoutText());
// Text with valid surrogates before and after the reveal index.
- const char16 valid_surrogates[] =
+ const base::char16 valid_surrogates[] =
{0xD800, 0xDC00, 'h', 'o', 'p', 0xD800, 0xDC00, 0};
render_text->SetText(valid_surrogates);
EXPECT_EQ(ASCIIToUTF16("*****"), render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(0);
- const char16 valid_expect_0_and_1[] = {0xD800, 0xDC00, '*', '*', '*', '*', 0};
+ const base::char16 valid_expect_0_and_1[] =
+ {0xD800, 0xDC00, '*', '*', '*', '*', 0};
EXPECT_EQ(valid_expect_0_and_1, render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(1);
EXPECT_EQ(valid_expect_0_and_1, render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(2);
EXPECT_EQ(ASCIIToUTF16("*h***"), render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(5);
- const char16 valid_expect_5_and_6[] = {'*', '*', '*', '*', 0xD800, 0xDC00, 0};
+ const base::char16 valid_expect_5_and_6[] =
+ {'*', '*', '*', '*', 0xD800, 0xDC00, 0};
EXPECT_EQ(valid_expect_5_and_6, render_text->GetLayoutText());
render_text->RenderText::SetObscuredRevealIndex(6);
EXPECT_EQ(valid_expect_5_and_6, render_text->GetLayoutText());
}
+TEST_F(RenderTextTest, ElidedText) {
+ // TODO(skanuj) : Add more test cases for following
+ // - RenderText styles.
+ // - Cross interaction of truncate, elide and obscure.
+ // - ElideText tests from text_elider.cc.
+ struct {
+ const wchar_t* text;
+ const wchar_t* layout_text;
+ const bool elision_expected;
+ } cases[] = {
+ // Strings shorter than the elision width should be laid out in full.
+ { L"", L"" , false },
+ { L"M", L"" , false },
+ { L" . ", L" . " , false },
+ { kWeak, kWeak , false },
+ { kLtr, kLtr , false },
+ { kLtrRtl, kLtrRtl , false },
+ { kLtrRtlLtr, kLtrRtlLtr, false },
+ { kRtl, kRtl , false },
+ { kRtlLtr, kRtlLtr , false },
+ { kRtlLtrRtl, kRtlLtrRtl, false },
+ // Strings as long as the elision width should be laid out in full.
+ { L"012ab", L"012ab" , false },
+ // Long strings should be elided with an ellipsis appended at the end.
+ { L"012abc", L"012a\x2026", true },
+ { L"012ab" L"\x5d0\x5d1", L"012a\x2026", true },
+ { L"012a" L"\x5d1" L"b", L"012a\x2026", true },
+ // No RLM marker added as digits (012) have weak directionality.
+ { L"01" L"\x5d0\x5d1\x5d2", L"01\x5d0\x5d1\x2026", true },
+ // RLM marker added as "ab" have strong LTR directionality.
+ { L"ab" L"\x5d0\x5d1\x5d2", L"ab\x5d0\x5d1\x2026\x200f", true },
+ // Complex script is not handled. In this example, the "\x0915\x093f" is a
+ // compound glyph, but only half of it is elided.
+ { L"0123\x0915\x093f", L"0123\x0915\x2026", true },
+ // Surrogate pairs should be elided reasonably enough.
+ { L"0\x05e9\x05bc\x05c1\x05b8", L"0\x05e9\x05bc\x05c1\x05b8", false },
+ { L"0\x05e9\x05bc\x05c1\x05b8", L"0\x05e9\x05bc\x2026" , true },
+ { L"01\x05e9\x05bc\x05c1\x05b8", L"01\x05e9\x2026" , true },
+ { L"012\x05e9\x05bc\x05c1\x05b8", L"012\x2026\x200E" , true },
+ { L"012\xF0\x9D\x84\x9E", L"012\xF0\x2026" , true },
+ };
+
+ scoped_ptr<RenderText> expected_render_text(RenderText::CreateInstance());
+ expected_render_text->SetFontList(FontList("serif, Sans serif, 12px"));
+ expected_render_text->SetDisplayRect(Rect(0, 0, 9999, 100));
+
+ scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
+ render_text->SetFontList(FontList("serif, Sans serif, 12px"));
+ render_text->SetElideBehavior(ELIDE_TAIL);
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
+ // Compute expected width
+ expected_render_text->SetText(WideToUTF16(cases[i].layout_text));
+ int expected_width = expected_render_text->GetContentWidth();
+
+ base::string16 input = WideToUTF16(cases[i].text);
+ // Extend the input text to ensure that it is wider than the layout_text,
+ // and so it will get elided.
+ if (cases[i].elision_expected)
+ input.append(WideToUTF16(L" MMMMMMMMMMM"));
+
+ render_text->SetText(input);
+ render_text->SetDisplayRect(Rect(0, 0, expected_width, 100));
+ EXPECT_EQ(input, render_text->text())
+ << "->For case " << i << ": " << cases[i].text << "\n";
+ EXPECT_EQ(WideToUTF16(cases[i].layout_text), render_text->GetLayoutText())
+ << "->For case " << i << ": " << cases[i].text << "\n";
+ expected_render_text->SetText(base::string16());
+ }
+}
+
+TEST_F(RenderTextTest, ElidedObscuredText) {
+ scoped_ptr<RenderText> expected_render_text(RenderText::CreateInstance());
+ expected_render_text->SetFontList(FontList("serif, Sans serif, 12px"));
+ expected_render_text->SetDisplayRect(Rect(0, 0, 9999, 100));
+ expected_render_text->SetText(WideToUTF16(L"**\x2026"));
+
+ scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
+ render_text->SetFontList(FontList("serif, Sans serif, 12px"));
+ render_text->SetElideBehavior(ELIDE_TAIL);
+ render_text->SetDisplayRect(
+ Rect(0, 0, expected_render_text->GetContentWidth(), 100));
+ render_text->SetObscured(true);
+ render_text->SetText(WideToUTF16(L"abcdef"));
+ EXPECT_EQ(WideToUTF16(L"abcdef"), render_text->text());
+ EXPECT_EQ(WideToUTF16(L"**\x2026"), render_text->GetLayoutText());
+}
+
TEST_F(RenderTextTest, TruncatedText) {
struct {
const wchar_t* text;
@@ -742,7 +828,7 @@ TEST_F(RenderTextTest, MoveCursorLeftRight_MeiryoUILigatures) {
scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
// Meiryo UI uses single-glyph ligatures for 'ff' and 'ffi', but each letter
// (code point) has unique bounds, so mid-glyph cursoring should be possible.
- render_text->SetFont(Font("Meiryo UI", 12));
+ render_text->SetFontList(FontList("Meiryo UI, 12px"));
render_text->SetText(WideToUTF16(L"ff ffi"));
EXPECT_EQ(0U, render_text->cursor_position());
for (size_t i = 0; i < render_text->text().length(); ++i) {
@@ -806,26 +892,74 @@ TEST_F(RenderTextTest, GraphemePositions) {
{ kText3, 50, 6, 6 },
};
- // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete
- // font support for some scripts - http://crbug.com/106450
#if defined(OS_WIN)
+ // TODO(msw): XP fails due to lack of font support: http://crbug.com/106450
if (base::win::GetVersion() < base::win::VERSION_VISTA)
return;
#endif
scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); i++) {
+ SCOPED_TRACE(base::StringPrintf("Testing cases[%" PRIuS "]", i));
render_text->SetText(cases[i].text);
size_t next = render_text->IndexOfAdjacentGrapheme(cases[i].index,
CURSOR_FORWARD);
EXPECT_EQ(cases[i].expected_next, next);
- EXPECT_TRUE(render_text->IsCursorablePosition(next));
+ EXPECT_TRUE(render_text->IsValidCursorIndex(next));
size_t previous = render_text->IndexOfAdjacentGrapheme(cases[i].index,
CURSOR_BACKWARD);
EXPECT_EQ(cases[i].expected_previous, previous);
- EXPECT_TRUE(render_text->IsCursorablePosition(previous));
+ EXPECT_TRUE(render_text->IsValidCursorIndex(previous));
+ }
+}
+
+TEST_F(RenderTextTest, MidGraphemeSelectionBounds) {
+#if defined(OS_WIN)
+ // TODO(msw): XP fails due to lack of font support: http://crbug.com/106450
+ if (base::win::GetVersion() < base::win::VERSION_VISTA)
+ return;
+#endif
+
+ // Test that selection bounds may be set amid multi-character graphemes.
+ const base::string16 kHindi = WideToUTF16(L"\x0915\x093f");
+ const base::string16 kThai = WideToUTF16(L"\x0e08\x0e33");
+ const base::string16 cases[] = { kHindi, kThai };
+
+ scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
+ for (size_t i = 0; i < arraysize(cases); i++) {
+ SCOPED_TRACE(base::StringPrintf("Testing cases[%" PRIuS "]", i));
+ render_text->SetText(cases[i]);
+ EXPECT_TRUE(render_text->IsValidLogicalIndex(1));
+#if !defined(OS_MACOSX)
+ EXPECT_FALSE(render_text->IsValidCursorIndex(1));
+#endif
+ EXPECT_TRUE(render_text->SelectRange(Range(2, 1)));
+ EXPECT_EQ(Range(2, 1), render_text->selection());
+ EXPECT_EQ(1U, render_text->cursor_position());
+ // Although selection bounds may be set within a multi-character grapheme,
+ // cursor movement (e.g. via arrow key) should avoid those indices.
+ render_text->MoveCursor(CHARACTER_BREAK, CURSOR_LEFT, false);
+ EXPECT_EQ(0U, render_text->cursor_position());
+ render_text->MoveCursor(CHARACTER_BREAK, CURSOR_RIGHT, false);
+ EXPECT_EQ(2U, render_text->cursor_position());
+ }
+}
+
+TEST_F(RenderTextTest, FindCursorPosition) {
+ const wchar_t* kTestStrings[] = { kLtrRtl, kLtrRtlLtr, kRtlLtr, kRtlLtrRtl };
+ scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
+ render_text->SetDisplayRect(Rect(0, 0, 100, 20));
+ for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ SCOPED_TRACE(base::StringPrintf("Testing case[%" PRIuS "]", i));
+ render_text->SetText(WideToUTF16(kTestStrings[i]));
+ for(size_t j = 0; j < render_text->text().length(); ++j) {
+ const Range range(render_text->GetGlyphBounds(j));
+ // Test a point just inside the leading edge of the glyph bounds.
+ int x = range.is_reversed() ? range.GetMax() - 1 : range.GetMin() + 1;
+ EXPECT_EQ(j, render_text->FindCursorPosition(Point(x, 0)).caret_pos());
+ }
}
}
@@ -855,9 +989,8 @@ TEST_F(RenderTextTest, EdgeSelectionModels) {
{ kHebrewLatin, base::i18n::RIGHT_TO_LEFT },
};
- // TODO(asvitkine): Disable tests that fail on XP bots due to lack of complete
- // font support for some scripts - http://crbug.com/106450
#if defined(OS_WIN)
+ // TODO(msw): XP fails due to lack of font support: http://crbug.com/106450
if (base::win::GetVersion() < base::win::VERSION_VISTA)
return;
#endif
@@ -1210,13 +1343,6 @@ TEST_F(RenderTextTest, StringSizeRespectsFontListMetrics) {
EXPECT_EQ(font_list.GetBaseline(), render_text->GetBaseline());
}
-TEST_F(RenderTextTest, SetFont) {
- scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
- render_text->SetFont(Font("Arial", 12));
- EXPECT_EQ("Arial", render_text->GetPrimaryFont().GetFontName());
- EXPECT_EQ(12, render_text->GetPrimaryFont().GetFontSize());
-}
-
TEST_F(RenderTextTest, SetFontList) {
scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
render_text->SetFontList(FontList("Arial,Symbol, 13px"));
@@ -1224,7 +1350,7 @@ TEST_F(RenderTextTest, SetFontList) {
ASSERT_EQ(2U, fonts.size());
EXPECT_EQ("Arial", fonts[0].GetFontName());
EXPECT_EQ("Symbol", fonts[1].GetFontName());
- EXPECT_EQ(13, render_text->GetPrimaryFont().GetFontSize());
+ EXPECT_EQ(13, render_text->font_list().GetFontSize());
}
TEST_F(RenderTextTest, StringSizeBoldWidth) {
@@ -1254,20 +1380,20 @@ TEST_F(RenderTextTest, StringSizeHeight) {
WideToUTF16(L"\x05e0\x05b8"), // Hebrew
};
- Font default_font;
- Font larger_font = default_font.DeriveFont(24, default_font.GetStyle());
- EXPECT_GT(larger_font.GetHeight(), default_font.GetHeight());
+ const FontList default_font_list;
+ 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 < ARRAYSIZE_UNSAFE(cases); i++) {
scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
- render_text->SetFont(default_font);
+ render_text->SetFontList(default_font_list);
render_text->SetText(cases[i]);
const int height1 = render_text->GetStringSize().height();
EXPECT_GT(height1, 0);
// Check that setting the larger font increases the height.
- render_text->SetFont(larger_font);
+ render_text->SetFontList(larger_font_list);
const int height2 = render_text->GetStringSize().height();
EXPECT_GT(height2, height1);
}
@@ -1364,8 +1490,8 @@ TEST_F(RenderTextTest, GetTextOffsetHorizontalDefaultInRTL) {
TEST_F(RenderTextTest, SameFontForParentheses) {
struct {
- const char16 left_char;
- const char16 right_char;
+ const base::char16 left_char;
+ const base::char16 right_char;
} punctuation_pairs[] = {
{ '(', ')' },
{ '{', '}' },
@@ -1642,11 +1768,7 @@ TEST_F(RenderTextTest, DisplayRectShowsCursorRTL) {
// Changing colors between or inside ligated glyphs should not break shaping.
TEST_F(RenderTextTest, SelectionKeepsLigatures) {
- const wchar_t* kTestStrings[] = {
- L"\x644\x623",
- L"\x633\x627"
- };
-
+ const wchar_t* kTestStrings[] = { L"\x644\x623", L"\x633\x627" };
scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
render_text->set_selection_color(SK_ColorRED);
Canvas canvas;
@@ -1656,8 +1778,7 @@ TEST_F(RenderTextTest, SelectionKeepsLigatures) {
const int expected_width = render_text->GetStringSize().width();
render_text->MoveCursorTo(SelectionModel(Range(0, 1), CURSOR_FORWARD));
EXPECT_EQ(expected_width, render_text->GetStringSize().width());
- // Draw the text. It shouldn't hit any DCHECKs or crash.
- // See http://crbug.com/214150
+ // Drawing the text should not DCHECK or crash; see http://crbug.com/262119
render_text->Draw(&canvas);
render_text->MoveCursorTo(SelectionModel(0, CURSOR_FORWARD));
}
@@ -1782,7 +1903,6 @@ TEST_F(RenderTextTest, Multiline_Newline) {
}
}
-
TEST_F(RenderTextTest, Win_BreakRunsByUnicodeBlocks) {
scoped_ptr<RenderTextWin> render_text(
static_cast<RenderTextWin*>(RenderText::CreateInstance()));
@@ -1804,4 +1924,120 @@ TEST_F(RenderTextTest, Win_BreakRunsByUnicodeBlocks) {
}
#endif // defined(OS_WIN)
+TEST_F(RenderTextTest, HarfBuzz_CharToGlyph) {
+ struct {
+ uint32 glyph_to_char[4];
+ size_t char_to_glyph_expected[4];
+ Range char_range_to_glyph_range_expected[4];
+ bool is_rtl;
+ } cases[] = {
+ { // From string "A B C D" to glyphs "a b c d".
+ { 0, 1, 2, 3 },
+ { 0, 1, 2, 3 },
+ { Range(0, 1), Range(1, 2), Range(2, 3), Range(3, 4) },
+ false
+ },
+ { // From string "A B C D" to glyphs "d b c a".
+ { 3, 2, 1, 0 },
+ { 3, 2, 1, 0 },
+ { Range(3, 4), Range(2, 3), Range(1, 2), Range(0, 1) },
+ true
+ },
+ { // From string "A B C D" to glyphs "ab c c d".
+ { 0, 2, 2, 3 },
+ { 0, 0, 1, 3 },
+ { Range(0, 1), Range(0, 1), Range(1, 3), Range(3, 4) },
+ false
+ },
+ { // From string "A B C D" to glyphs "d c c ba".
+ { 3, 2, 2, 0 },
+ { 3, 3, 1, 0 },
+ { Range(3, 4), Range(3, 4), Range(1, 3), Range(0, 1) },
+ true
+ },
+ };
+
+ internal::TextRunHarfBuzz run;
+ run.range = Range(0, 4);
+ run.glyph_count = 4;
+ run.glyph_to_char.reset(new uint32[4]);
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ std::copy(cases[i].glyph_to_char, cases[i].glyph_to_char + 4,
+ run.glyph_to_char.get());
+ run.is_rtl = cases[i].is_rtl;
+ for (size_t j = 0; j < 4; ++j) {
+ SCOPED_TRACE(base::StringPrintf("Case %" PRIuS ", char %" PRIuS, i, j));
+ EXPECT_EQ(cases[i].char_to_glyph_expected[j], run.CharToGlyph(j));
+ EXPECT_EQ(cases[i].char_range_to_glyph_range_expected[j],
+ run.CharRangeToGlyphRange(Range(j, j + 1)));
+ }
+ }
+}
+
+TEST_F(RenderTextTest, HarfBuzz_RunDirection) {
+ RenderTextHarfBuzz render_text;
+ const base::string16 mixed =
+ WideToUTF16(L"\x05D0\x05D1" L"1234" L"\x05D2\x05D3");
+ render_text.SetText(mixed);
+ render_text.EnsureLayout();
+ ASSERT_EQ(3U, render_text.runs_.size());
+ EXPECT_TRUE(render_text.runs_[0]->is_rtl);
+ EXPECT_FALSE(render_text.runs_[1]->is_rtl);
+ EXPECT_TRUE(render_text.runs_[2]->is_rtl);
+}
+
+TEST_F(RenderTextTest, HarfBuzz_BreakRunsByUnicodeBlocks) {
+ RenderTextHarfBuzz render_text;
+
+ // The '\x25B6' "play character" should break runs. http://crbug.com/278913
+ render_text.SetText(WideToUTF16(L"x\x25B6y"));
+ render_text.EnsureLayout();
+ ASSERT_EQ(3U, render_text.runs_.size());
+ EXPECT_EQ(Range(0, 1), render_text.runs_[0]->range);
+ EXPECT_EQ(Range(1, 2), render_text.runs_[1]->range);
+ EXPECT_EQ(Range(2, 3), render_text.runs_[2]->range);
+
+ render_text.SetText(WideToUTF16(L"x \x25B6 y"));
+ render_text.EnsureLayout();
+ ASSERT_EQ(3U, render_text.runs_.size());
+ EXPECT_EQ(Range(0, 2), render_text.runs_[0]->range);
+ EXPECT_EQ(Range(2, 3), render_text.runs_[1]->range);
+ EXPECT_EQ(Range(3, 5), render_text.runs_[2]->range);
+}
+
+// Disabled on Mac because RenderTextMac doesn't implement GetGlyphBounds.
+#if !defined(OS_MACOSX)
+TEST_F(RenderTextTest, GlyphBounds) {
+ const wchar_t* kTestStrings[] = {
+ L"asdf 1234 qwer", L"\x0647\x0654", L"\x0645\x0631\x062D\x0628\x0627"
+ };
+ scoped_ptr<RenderText> render_text(RenderText::CreateInstance());
+
+ for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ render_text->SetText(WideToUTF16(kTestStrings[i]));
+ render_text->EnsureLayout();
+
+ for (size_t j = 0; j < render_text->text().length(); ++j)
+ EXPECT_FALSE(render_text->GetGlyphBounds(j).is_empty());
+ }
+}
+#endif
+
+// Remove this after making RTHB default in favor of RenderTextTest.GlyphBounds.
+TEST_F(RenderTextTest, HarfBuzz_GlyphBounds) {
+ const wchar_t* kTestStrings[] = {
+ L"asdf 1234 qwer", L"\x0647\x0654", L"\x0645\x0631\x062D\x0628\x0627"
+ };
+ scoped_ptr<RenderText> render_text(new RenderTextHarfBuzz);
+
+ for (size_t i = 0; i < arraysize(kTestStrings); ++i) {
+ render_text->SetText(WideToUTF16(kTestStrings[i]));
+ render_text->EnsureLayout();
+
+ for (size_t j = 0; j < render_text->text().length(); ++j)
+ EXPECT_FALSE(render_text->GetGlyphBounds(j).is_empty());
+ }
+}
+
} // namespace gfx
diff --git a/chromium/ui/gfx/render_text_win.cc b/chromium/ui/gfx/render_text_win.cc
index 4afbc7fa71e..f79577fde0a 100644
--- a/chromium/ui/gfx/render_text_win.cc
+++ b/chromium/ui/gfx/render_text_win.cc
@@ -86,7 +86,8 @@ bool ChooseFallbackFont(HDC hdc,
log_font.lfFaceName[0] = 0;
EnumEnhMetaFile(0, meta_file, MetaFileEnumProc, &log_font, NULL);
if (log_font.lfFaceName[0]) {
- *result = Font(UTF16ToUTF8(log_font.lfFaceName), font.GetFontSize());
+ *result = Font(base::UTF16ToUTF8(log_font.lfFaceName),
+ font.GetFontSize());
found_fallback = true;
}
}
@@ -117,11 +118,11 @@ void DeriveFontIfNecessary(int font_size,
const int current_style = (font->GetStyle() & kStyleMask);
const int current_size = font->GetFontSize();
if (current_style != target_style || current_size != font_size)
- *font = font->DeriveFont(font_size - current_size, target_style);
+ *font = font->Derive(font_size - current_size, target_style);
}
// Returns true if |c| is a Unicode BiDi control character.
-bool IsUnicodeBidiControlCharacter(char16 c) {
+bool IsUnicodeBidiControlCharacter(base::char16 c) {
return c == base::i18n::kRightToLeftMark ||
c == base::i18n::kLeftToRightMark ||
c == base::i18n::kLeftToRightEmbeddingMark ||
@@ -263,6 +264,26 @@ bool IsUnusualBlockCode(const UBlockCode block_code) {
block_code == UBLOCK_MISCELLANEOUS_SYMBOLS;
}
+// Returns the index of the first unusual character after a usual character or
+// vice versa. Unusual characters are defined by |IsUnusualBlockCode|.
+size_t FindUnusualCharacter(const base::string16& text,
+ size_t run_start,
+ size_t run_break) {
+ const int32 run_length = static_cast<int32>(run_break - run_start);
+ base::i18n::UTF16CharIterator iter(text.c_str() + run_start,
+ run_length);
+ const UBlockCode first_block_code = ublock_getCode(iter.get());
+ const bool first_block_unusual = IsUnusualBlockCode(first_block_code);
+ while (iter.Advance() && iter.array_pos() < run_length) {
+ const UBlockCode current_block_code = ublock_getCode(iter.get());
+ if (current_block_code != first_block_code &&
+ (first_block_unusual || IsUnusualBlockCode(current_block_code))) {
+ return run_start + iter.array_pos();
+ }
+ }
+ return run_break;
+}
+
} // namespace
namespace internal {
@@ -503,19 +524,14 @@ HDC RenderTextWin::cached_hdc_ = NULL;
// static
std::map<std::string, Font> RenderTextWin::successful_substitute_fonts_;
-RenderTextWin::RenderTextWin()
- : RenderText(),
- needs_layout_(false) {
+RenderTextWin::RenderTextWin() : RenderText(), needs_layout_(false) {
set_truncate_length(kMaxUniscribeTextLength);
-
memset(&script_control_, 0, sizeof(script_control_));
memset(&script_state_, 0, sizeof(script_state_));
-
MoveCursorTo(EdgeSelectionModel(CURSOR_LEFT));
}
-RenderTextWin::~RenderTextWin() {
-}
+RenderTextWin::~RenderTextWin() {}
Size RenderTextWin::GetStringSize() {
EnsureLayout();
@@ -662,6 +678,7 @@ SelectionModel RenderTextWin::AdjacentWordSelectionModel(
}
Range RenderTextWin::GetGlyphBounds(size_t index) {
+ EnsureLayout();
const size_t run_index =
GetRunContainingCaret(SelectionModel(index, CURSOR_FORWARD));
// Return edge bounds if the index is invalid or beyond the layout text size.
@@ -715,7 +732,7 @@ std::vector<Rect> RenderTextWin::GetSubstringBounds(const Range& range) {
size_t RenderTextWin::TextIndexToLayoutIndex(size_t index) const {
DCHECK_LE(index, text().length());
- ptrdiff_t i = obscured() ? gfx::UTF16IndexToOffset(text(), 0, index) : index;
+ ptrdiff_t i = obscured() ? UTF16IndexToOffset(text(), 0, index) : index;
CHECK_GE(i, 0);
// Clamp layout indices to the length of the text actually used for layout.
return std::min<size_t>(GetLayoutText().length(), i);
@@ -726,24 +743,22 @@ size_t RenderTextWin::LayoutIndexToTextIndex(size_t index) const {
return index;
DCHECK_LE(index, GetLayoutText().length());
- const size_t text_index = gfx::UTF16OffsetToIndex(text(), 0, index);
+ const size_t text_index = UTF16OffsetToIndex(text(), 0, index);
DCHECK_LE(text_index, text().length());
return text_index;
}
-bool RenderTextWin::IsCursorablePosition(size_t position) {
- if (position == 0 || position == text().length())
+bool RenderTextWin::IsValidCursorIndex(size_t index) {
+ if (index == 0 || index == text().length())
return true;
+ if (!IsValidLogicalIndex(index))
+ return false;
EnsureLayout();
-
- // Check that the index is at a valid code point (not mid-surrgate-pair),
- // that it is not truncated from layout text (its glyph is shown on screen),
- // and that its glyph has distinct bounds (not mid-multi-character-grapheme).
- // An example of a multi-character-grapheme that is not a surrogate-pair is:
- // \x0915\x093f - (ki) - one of many Devanagari biconsonantal conjuncts.
- return gfx::IsValidCodePointIndex(text(), position) &&
- position < LayoutIndexToTextIndex(GetLayoutText().length()) &&
- GetGlyphBounds(position) != GetGlyphBounds(position - 1);
+ // Disallow indices amid multi-character graphemes by checking glyph bounds.
+ // These characters are not surrogate-pairs, but may yield a single glyph:
+ // \x0915\x093f - (ki) - one of many Devanagari biconsonantal conjuncts.
+ // \x0e08\x0e33 - (cho chan + sara am) - a Thai consonant and vowel pair.
+ return GetGlyphBounds(index) != GetGlyphBounds(index - 1);
}
void RenderTextWin::ResetLayout() {
@@ -799,7 +814,8 @@ void RenderTextWin::DrawVisualText(Canvas* canvas) {
GetCachedFontSmoothingSettings(&smoothing_enabled, &cleartype_enabled);
// Note that |cleartype_enabled| corresponds to Skia's |enable_lcd_text|.
renderer.SetFontSmoothingSettings(
- smoothing_enabled, cleartype_enabled && !background_is_transparent());
+ smoothing_enabled, cleartype_enabled && !background_is_transparent(),
+ smoothing_enabled /* subpixel_positioning */);
ApplyCompositionAndSelectionStyles();
@@ -841,7 +857,7 @@ void RenderTextWin::DrawVisualText(Canvas* canvas) {
for (size_t k = glyph_range.start(); k < glyph_range.end(); ++k) {
pos[k - glyph_range.start()].set(
SkIntToScalar(text_offset.x() + run->offsets[k].du + segment_x),
- SkIntToScalar(text_offset.y() + run->offsets[k].dv));
+ SkIntToScalar(text_offset.y() - run->offsets[k].dv));
segment_x += run->advance_widths[k];
}
pos.back().set(SkIntToScalar(text_offset.x() + segment_x),
@@ -858,8 +874,13 @@ void RenderTextWin::DrawVisualText(Canvas* canvas) {
const Range intersection =
colors().GetRange(it).Intersect(segment->char_range);
const Range colored_glyphs = CharRangeToGlyphRange(*run, intersection);
+ // The range may be empty if a portion of a multi-character grapheme is
+ // selected, yielding two colors for a single glyph. For now, this just
+ // paints the glyph with a single style, but it should paint it twice,
+ // clipped according to selection bounds. See http://crbug.com/366786
+ if (colored_glyphs.is_empty())
+ continue;
DCHECK(glyph_range.Contains(colored_glyphs));
- DCHECK(!colored_glyphs.is_empty());
const SkPoint& start_pos =
pos[colored_glyphs.start() - glyph_range.start()];
const SkPoint& end_pos =
@@ -876,6 +897,8 @@ void RenderTextWin::DrawVisualText(Canvas* canvas) {
preceding_segment_widths += segment_width;
}
+
+ renderer.EndDiagonalStrike();
}
UndoCompositionAndSelectionStyles();
@@ -926,7 +949,7 @@ void RenderTextWin::ItemizeLogicalText() {
for (size_t run_break = 0; run_break < layout_text_length;) {
internal::TextRun* run = new internal::TextRun();
run->range.set_start(run_break);
- run->font = GetPrimaryFont();
+ run->font = font_list().GetPrimaryFont();
run->font_style = (style.style(BOLD) ? Font::BOLD : 0) |
(style.style(ITALIC) ? Font::ITALIC : 0);
DeriveFontIfNecessary(run->font.GetFontSize(), run->font.GetHeight(),
@@ -952,20 +975,8 @@ void RenderTextWin::ItemizeLogicalText() {
// This avoids using their fallback fonts for more characters than needed,
// in cases like "\x25B6 Media Title", etc. http://crbug.com/278913
if (run_break > run->range.start()) {
- const size_t run_start = run->range.start();
- const int32 run_length = static_cast<int32>(run_break - run_start);
- base::i18n::UTF16CharIterator iter(layout_text.c_str() + run_start,
- run_length);
- const UBlockCode first_block_code = ublock_getCode(iter.get());
- const bool first_block_unusual = IsUnusualBlockCode(first_block_code);
- while (iter.Advance() && iter.array_pos() < run_length) {
- const UBlockCode current_block_code = ublock_getCode(iter.get());
- if (current_block_code != first_block_code &&
- (first_block_unusual || IsUnusualBlockCode(current_block_code))) {
- run_break = run_start + iter.array_pos();
- break;
- }
- }
+ run_break =
+ FindUnusualCharacter(layout_text, run->range.start(), run_break);
}
DCHECK(IsValidCodePointIndex(layout_text, run_break));
@@ -1271,7 +1282,7 @@ SelectionModel RenderTextWin::LastSelectionModelInsideRun(
return SelectionModel(position, CURSOR_FORWARD);
}
-RenderText* RenderText::CreateInstance() {
+RenderText* RenderText::CreateNativeInstance() {
return new RenderTextWin;
}
diff --git a/chromium/ui/gfx/render_text_win.h b/chromium/ui/gfx/render_text_win.h
index 1a1ba4805cb..4e8caf6484d 100644
--- a/chromium/ui/gfx/render_text_win.h
+++ b/chromium/ui/gfx/render_text_win.h
@@ -80,7 +80,7 @@ class RenderTextWin : public RenderText {
virtual std::vector<Rect> GetSubstringBounds(const Range& range) OVERRIDE;
virtual size_t TextIndexToLayoutIndex(size_t index) const OVERRIDE;
virtual size_t LayoutIndexToTextIndex(size_t index) const OVERRIDE;
- virtual bool IsCursorablePosition(size_t position) OVERRIDE;
+ virtual bool IsValidCursorIndex(size_t index) OVERRIDE;
virtual void ResetLayout() OVERRIDE;
virtual void EnsureLayout() OVERRIDE;
virtual void DrawVisualText(Canvas* canvas) OVERRIDE;
diff --git a/chromium/ui/gfx/safe_integer_conversions.h b/chromium/ui/gfx/safe_integer_conversions.h
index 523b1f3441f..ea9fde726a8 100644
--- a/chromium/ui/gfx/safe_integer_conversions.h
+++ b/chromium/ui/gfx/safe_integer_conversions.h
@@ -1,54 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_SAFE_INTEGER_CONVERSIONS_H_
-#define UI_GFX_SAFE_INTEGER_CONVERSIONS_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/safe_integer_conversions.h"
-#include <cmath>
-#include <limits>
-
-#include "ui/gfx/gfx_export.h"
-
-namespace gfx {
-
-inline int ClampToInt(float value) {
- if (value != value)
- return 0; // no int NaN.
- if (value >= std::numeric_limits<int>::max())
- return std::numeric_limits<int>::max();
- if (value <= std::numeric_limits<int>::min())
- return std::numeric_limits<int>::min();
- return static_cast<int>(value);
-}
-
-inline int ToFlooredInt(float value) {
- return ClampToInt(std::floor(value));
-}
-
-inline int ToCeiledInt(float value) {
- return ClampToInt(std::ceil(value));
-}
-
-inline int ToRoundedInt(float value) {
- float rounded;
- if (value >= 0.0f)
- rounded = std::floor(value + 0.5f);
- else
- rounded = std::ceil(value - 0.5f);
- return ClampToInt(rounded);
-}
-
-inline bool IsExpressibleAsInt(float value) {
- if (value != value)
- return false; // no int NaN.
- if (value > std::numeric_limits<int>::max())
- return false;
- if (value < std::numeric_limits<int>::min())
- return false;
- return true;
-}
-
-} // namespace gfx
-
-#endif // UI_GFX_SAFE_INTEGER_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/scoped_gobject.h b/chromium/ui/gfx/scoped_gobject.h
deleted file mode 100644
index 860849ec84e..00000000000
--- a/chromium/ui/gfx/scoped_gobject.h
+++ /dev/null
@@ -1,34 +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_SCOPED_GOBJECT_H_
-#define UI_GFX_SCOPED_GOBJECT_H_
-
-#include <glib-object.h>
-
-#include "base/memory/scoped_ptr.h"
-
-namespace ui {
-
-// It's not legal C++ to have a templatized typedefs, so we wrap it in a
-// struct. When using this, you need to include ::Type. E.g.,
-// ScopedGObject<GdkPixbufLoader>::Type loader(gdk_pixbuf_loader_new());
-template<class T>
-struct ScopedGObject {
- // A helper class that will g_object_unref |p| when it goes out of scope.
- // This never adds a ref, it only unrefs.
- template<class U>
- struct GObjectUnrefer {
- void operator()(U* ptr) const {
- if (ptr)
- g_object_unref(ptr);
- }
- };
-
- typedef scoped_ptr_malloc<T, GObjectUnrefer<T> > Type;
-};
-
-} // namespace ui
-
-#endif // UI_GFX_SCOPED_GOBJECT_H_
diff --git a/chromium/ui/gfx/screen_android.cc b/chromium/ui/gfx/screen_android.cc
index e90bb76725d..9114b855453 100644
--- a/chromium/ui/gfx/screen_android.cc
+++ b/chromium/ui/gfx/screen_android.cc
@@ -43,6 +43,7 @@ class ScreenAndroid : public Screen {
gfx::Display display(0, bounds_in_dip);
if (!gfx::Display::HasForceDeviceScaleFactor())
display.set_device_scale_factor(device_scale_factor);
+ display.SetRotationAsDegree(device_info.GetRotationDegrees());
return display;
}
diff --git a/chromium/ui/gfx/screen_gtk.cc b/chromium/ui/gfx/screen_gtk.cc
deleted file mode 100644
index ac2464bbbd7..00000000000
--- a/chromium/ui/gfx/screen_gtk.cc
+++ /dev/null
@@ -1,210 +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 "ui/gfx/screen.h"
-
-#include <gdk/gdkx.h>
-#include <gtk/gtk.h>
-
-#include "base/logging.h"
-#include "ui/gfx/display.h"
-
-namespace {
-
-bool GetScreenWorkArea(gfx::Rect* out_rect) {
- gboolean ok;
- guchar* raw_data = NULL;
- gint data_len = 0;
- ok = gdk_property_get(gdk_get_default_root_window(), // a gdk window
- gdk_atom_intern("_NET_WORKAREA", FALSE), // property
- gdk_atom_intern("CARDINAL", FALSE), // property type
- 0, // byte offset into property
- 0xff, // property length to retrieve
- false, // delete property after retrieval?
- NULL, // returned property type
- NULL, // returned data format
- &data_len, // returned data len
- &raw_data); // returned data
- if (!ok)
- return false;
-
- // We expect to get four longs back: x, y, width, height.
- if (data_len < static_cast<gint>(4 * sizeof(glong))) {
- NOTREACHED();
- g_free(raw_data);
- return false;
- }
-
- glong* data = reinterpret_cast<glong*>(raw_data);
- gint x = data[0];
- gint y = data[1];
- gint width = data[2];
- gint height = data[3];
- g_free(raw_data);
-
- out_rect->SetRect(x, y, width, height);
- return true;
-}
-
-gfx::Display GetDisplayForMonitorNum(GdkScreen* screen, gint monitor_num) {
- GdkRectangle bounds;
- gdk_screen_get_monitor_geometry(screen, monitor_num, &bounds);
- // Use |monitor_num| as display id.
- gfx::Display display(monitor_num, gfx::Rect(bounds));
- if (gdk_screen_get_primary_monitor(screen) == monitor_num) {
- gfx::Rect rect;
- if (GetScreenWorkArea(&rect))
- display.set_work_area(gfx::IntersectRects(rect, display.bounds()));
- }
- return display;
-}
-
-gfx::Display GetMonitorAreaNearestWindow(gfx::NativeView view) {
- GdkScreen* screen = gdk_screen_get_default();
- gint monitor_num = 0;
- if (view && GTK_IS_WINDOW(view)) {
- GtkWidget* top_level = gtk_widget_get_toplevel(view);
- DCHECK(GTK_IS_WINDOW(top_level));
- GtkWindow* window = GTK_WINDOW(top_level);
- screen = gtk_window_get_screen(window);
- monitor_num = gdk_screen_get_monitor_at_window(
- screen,
- gtk_widget_get_window(top_level));
- }
- return GetDisplayForMonitorNum(screen, monitor_num);
-}
-
-class ScreenGtk : public gfx::Screen {
- public:
- ScreenGtk() {
- }
-
- virtual ~ScreenGtk() {
- }
-
- virtual bool IsDIPEnabled() OVERRIDE {
- return false;
- }
-
- virtual gfx::Point GetCursorScreenPoint() OVERRIDE {
- gint x, y;
- gdk_display_get_pointer(gdk_display_get_default(), NULL, &x, &y, NULL);
- return gfx::Point(x, y);
- }
-
- // Returns the window under the cursor.
- virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE {
- GdkWindow* window = gdk_window_at_pointer(NULL, NULL);
- if (!window)
- return NULL;
-
- gpointer data = NULL;
- gdk_window_get_user_data(window, &data);
- GtkWidget* widget = reinterpret_cast<GtkWidget*>(data);
- if (!widget)
- return NULL;
- widget = gtk_widget_get_toplevel(widget);
- return GTK_IS_WINDOW(widget) ? GTK_WINDOW(widget) : NULL;
- }
-
- virtual gfx::NativeWindow GetWindowAtScreenPoint(const gfx::Point& point)
- OVERRIDE {
- NOTIMPLEMENTED();
- return NULL;
- }
-
- // Returns the number of displays.
- // Mirrored displays are excluded; this method is intended to return the
- // number of distinct, usable displays.
- virtual int GetNumDisplays() const OVERRIDE {
- // This query is kinda bogus for Linux -- do we want number of X screens?
- // The number of monitors Xinerama has? We'll just use whatever GDK uses.
- GdkScreen* screen = gdk_screen_get_default();
- return gdk_screen_get_n_monitors(screen);
- }
-
- virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE {
- GdkScreen* screen = gdk_screen_get_default();
- gint num_of_displays = gdk_screen_get_n_monitors(screen);
- std::vector<gfx::Display> all_displays;
- for (gint i = 0; i < num_of_displays; ++i)
- all_displays.push_back(GetDisplayForMonitorNum(screen, i));
- return all_displays;
- }
-
- // Returns the display nearest the specified window.
- virtual gfx::Display GetDisplayNearestWindow(
- gfx::NativeView view) const OVERRIDE {
- // Do not use the _NET_WORKAREA here, this is supposed to be an area on a
- // specific monitor, and _NET_WORKAREA is a hint from the WM that
- // generally spans across all monitors. This would make the work area
- // larger than the monitor.
- // TODO(danakj) This is a work-around as there is no standard way to get
- // this area, but it is a rect that we should be computing. The standard
- // means to compute this rect would be to watch all windows with
- // _NET_WM_STRUT(_PARTIAL) hints, and subtract their space from the
- // physical area of the display to construct a work area.
- // TODO(oshima): Implement Observer.
- return GetMonitorAreaNearestWindow(view);
- }
-
- // Returns the the display nearest the specified point.
- virtual gfx::Display GetDisplayNearestPoint(
- const gfx::Point& point) const OVERRIDE {
- GdkScreen* screen = gdk_screen_get_default();
- gint monitor = gdk_screen_get_monitor_at_point(
- screen, point.x(), point.y());
- // TODO(oshima): Implement Observer.
- return GetDisplayForMonitorNum(screen, monitor);
- }
-
- // Returns the display that most closely intersects the provided bounds.
- virtual gfx::Display GetDisplayMatching(
- const gfx::Rect& match_rect) const OVERRIDE {
- std::vector<gfx::Display> displays = GetAllDisplays();
- gfx::Display maxIntersectDisplay;
- gfx::Rect maxIntersection;
- for (std::vector<gfx::Display>::iterator it = displays.begin();
- it != displays.end(); ++it) {
- gfx::Rect displayIntersection = it->bounds();
- displayIntersection.Intersect(match_rect);
- if (displayIntersection.size().GetArea() >
- maxIntersection.size().GetArea()) {
- maxIntersectDisplay = *it;
- maxIntersection = displayIntersection;
- }
- }
- return maxIntersectDisplay.is_valid() ?
- maxIntersectDisplay : GetPrimaryDisplay();
- }
-
- // Returns the primary display.
- virtual gfx::Display GetPrimaryDisplay() const OVERRIDE {
- GdkScreen* screen = gdk_screen_get_default();
- gint primary_monitor_index = gdk_screen_get_primary_monitor(screen);
- // TODO(oshima): Implement Observer.
- return GetDisplayForMonitorNum(screen, primary_monitor_index);
- }
-
- virtual void AddObserver(gfx::DisplayObserver* observer) OVERRIDE {
- // TODO(oshima): crbug.com/122863.
- }
-
- virtual void RemoveObserver(gfx::DisplayObserver* observer) OVERRIDE {
- // TODO(oshima): crbug.com/122863.
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(ScreenGtk);
-};
-
-} // namespace
-
-namespace gfx {
-
-Screen* CreateNativeScreen() {
- return new ScreenGtk;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/screen_ios.mm b/chromium/ui/gfx/screen_ios.mm
index a2770298ca8..f630f00a9f0 100644
--- a/chromium/ui/gfx/screen_ios.mm
+++ b/chromium/ui/gfx/screen_ios.mm
@@ -69,7 +69,8 @@ class ScreenIos : public gfx::Screen {
// Returns the primary display.
virtual gfx::Display GetPrimaryDisplay() const OVERRIDE {
- UIScreen* mainScreen = [[UIScreen screens] objectAtIndex:0];
+ UIScreen* mainScreen = [UIScreen mainScreen];
+ CHECK(mainScreen);
gfx::Display display(0, gfx::Rect(mainScreen.bounds));
display.set_device_scale_factor([mainScreen scale]);
return display;
diff --git a/chromium/ui/gfx/screen_mac.mm b/chromium/ui/gfx/screen_mac.mm
index 51c0b665b7e..377c8592210 100644
--- a/chromium/ui/gfx/screen_mac.mm
+++ b/chromium/ui/gfx/screen_mac.mm
@@ -154,7 +154,10 @@ class ScreenMac : public gfx::Screen {
virtual gfx::Display GetDisplayNearestWindow(
gfx::NativeView view) const OVERRIDE {
- NSWindow* window = [view window];
+ NSWindow* window = nil;
+#if !defined(USE_AURA)
+ window = [view window];
+#endif
if (!window)
return GetPrimaryDisplay();
NSScreen* match_screen = [window screen];
@@ -209,8 +212,10 @@ class ScreenMac : public gfx::Screen {
namespace gfx {
+#if !defined(USE_AURA)
Screen* CreateNativeScreen() {
return new ScreenMac;
}
+#endif
}
diff --git a/chromium/ui/gfx/screen_win.cc b/chromium/ui/gfx/screen_win.cc
index 7903cc5fdd5..4530642e24b 100644
--- a/chromium/ui/gfx/screen_win.cc
+++ b/chromium/ui/gfx/screen_win.cc
@@ -19,13 +19,14 @@ MONITORINFOEX GetMonitorInfoForMonitor(HMONITOR monitor) {
MONITORINFOEX monitor_info;
ZeroMemory(&monitor_info, sizeof(MONITORINFOEX));
monitor_info.cbSize = sizeof(monitor_info);
- base::win::GetMonitorInfoWrapper(monitor, &monitor_info);
+ GetMonitorInfo(monitor, &monitor_info);
return monitor_info;
}
gfx::Display GetDisplay(MONITORINFOEX& monitor_info) {
// TODO(oshima): Implement Observer.
- int64 id = static_cast<int64>(base::Hash(WideToUTF8(monitor_info.szDevice)));
+ int64 id = static_cast<int64>(
+ base::Hash(base::WideToUTF8(monitor_info.szDevice)));
gfx::Rect bounds = gfx::Rect(monitor_info.rcMonitor);
gfx::Display display(id, bounds);
display.set_work_area(gfx::Rect(monitor_info.rcWork));
@@ -64,7 +65,8 @@ bool ScreenWin::IsDIPEnabled() {
gfx::Point ScreenWin::GetCursorScreenPoint() {
POINT pt;
GetCursorPos(&pt);
- return gfx::Point(pt);
+ gfx::Point cursor_pos_pixels(pt);
+ return gfx::win::ScreenToDIPPoint(cursor_pos_pixels);
}
gfx::NativeWindow ScreenWin::GetWindowUnderCursor() {
@@ -74,7 +76,8 @@ gfx::NativeWindow ScreenWin::GetWindowUnderCursor() {
}
gfx::NativeWindow ScreenWin::GetWindowAtScreenPoint(const gfx::Point& point) {
- return GetNativeWindowFromHWND(WindowFromPoint(point.ToPOINT()));
+ gfx::Point point_in_pixels = gfx::win::DIPToScreenPoint(point);
+ return GetNativeWindowFromHWND(WindowFromPoint(point_in_pixels.ToPOINT()));
}
int ScreenWin::GetNumDisplays() const {
@@ -99,8 +102,8 @@ gfx::Display ScreenWin::GetDisplayNearestWindow(gfx::NativeView window) const {
MONITORINFOEX monitor_info;
monitor_info.cbSize = sizeof(monitor_info);
- base::win::GetMonitorInfoWrapper(
- MonitorFromWindow(window_hwnd, MONITOR_DEFAULTTONEAREST), &monitor_info);
+ GetMonitorInfo(MonitorFromWindow(window_hwnd, MONITOR_DEFAULTTONEAREST),
+ &monitor_info);
return GetDisplay(monitor_info);
}
@@ -110,7 +113,7 @@ gfx::Display ScreenWin::GetDisplayNearestPoint(const gfx::Point& point) const {
MONITORINFOEX mi;
ZeroMemory(&mi, sizeof(MONITORINFOEX));
mi.cbSize = sizeof(mi);
- if (monitor && base::win::GetMonitorInfoWrapper(monitor, &mi)) {
+ if (monitor && GetMonitorInfo(monitor, &mi)) {
return GetDisplay(mi);
}
return gfx::Display();
@@ -129,7 +132,7 @@ gfx::Display ScreenWin::GetPrimaryDisplay() const {
gfx::Display display = GetDisplay(mi);
// TODO(kevers|girard): Test if these checks can be reintroduced for high-DIP
// once more of the app is DIP-aware.
- if (!IsInHighDPIMode()) {
+ if (!(IsInHighDPIMode() || IsHighDPIEnabled())) {
DCHECK_EQ(GetSystemMetrics(SM_CXSCREEN), display.size().width());
DCHECK_EQ(GetSystemMetrics(SM_CYSCREEN), display.size().height());
}
@@ -145,27 +148,13 @@ void ScreenWin::RemoveObserver(DisplayObserver* observer) {
}
HWND ScreenWin::GetHWNDFromNativeView(NativeView window) const {
-#if defined(USE_AURA)
NOTREACHED();
return NULL;
-#else
- return window;
-#endif // USE_AURA
}
NativeWindow ScreenWin::GetNativeWindowFromHWND(HWND hwnd) const {
-#if defined(USE_AURA)
NOTREACHED();
return NULL;
-#else
- return hwnd;
-#endif // USE_AURA
}
-#if !defined(USE_AURA)
-Screen* CreateNativeScreen() {
- return new ScreenWin;
-}
-#endif // !USE_AURA
-
} // namespace gfx
diff --git a/chromium/ui/gfx/selection_model.h b/chromium/ui/gfx/selection_model.h
index d509e898a99..356416df9c3 100644
--- a/chromium/ui/gfx/selection_model.h
+++ b/chromium/ui/gfx/selection_model.h
@@ -73,19 +73,16 @@ class GFX_EXPORT SelectionModel {
size_t caret_pos() const { return selection_.end(); }
LogicalCursorDirection caret_affinity() const { return caret_affinity_; }
+ // WARNING: Generally the selection start should not be changed without
+ // considering the effect on the caret affinity.
+ void set_selection_start(size_t pos) { selection_.set_start(pos); }
+
bool operator==(const SelectionModel& sel) const;
bool operator!=(const SelectionModel& sel) const { return !(*this == sel); }
std::string ToString() const;
private:
- friend class RenderText;
-
- // TODO(benrg): Generally the selection start should not be changed without
- // considering the effect on the caret affinity. This setter is exposed only
- // to RenderText to discourage misuse, and should probably be removed.
- void set_selection_start(size_t pos) { selection_.set_start(pos); }
-
// Logical selection. The logical caret position is the end of the selection.
Range selection_;
diff --git a/chromium/ui/gfx/size.h b/chromium/ui/gfx/size.h
index c96f5897f3b..78457d5088d 100644
--- a/chromium/ui/gfx/size.h
+++ b/chromium/ui/gfx/size.h
@@ -1,67 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_SIZE_H_
-#define UI_GFX_SIZE_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/size.h"
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/size_base.h"
-#include "ui/gfx/size_f.h"
-
-#if defined(OS_WIN)
-typedef struct tagSIZE SIZE;
-#elif defined(OS_IOS)
-#include <CoreGraphics/CoreGraphics.h>
-#elif defined(OS_MACOSX)
-#include <ApplicationServices/ApplicationServices.h>
-#endif
-
-namespace gfx {
-
-// A size has width and height values.
-class GFX_EXPORT Size : public SizeBase<Size, int> {
- public:
- Size() : SizeBase<Size, int>(0, 0) {}
- Size(int width, int height) : SizeBase<Size, int>(width, height) {}
-#if defined(OS_MACOSX)
- explicit Size(const CGSize& s);
-#endif
-
- ~Size() {}
-
-#if defined(OS_MACOSX)
- Size& operator=(const CGSize& s);
-#endif
-
-#if defined(OS_WIN)
- SIZE ToSIZE() const;
-#elif defined(OS_MACOSX)
- CGSize ToCGSize() const;
-#endif
-
- operator SizeF() const {
- return SizeF(width(), height());
- }
-
- std::string ToString() const;
-};
-
-inline bool operator==(const Size& lhs, const Size& rhs) {
- return lhs.width() == rhs.width() && lhs.height() == rhs.height();
-}
-
-inline bool operator!=(const Size& lhs, const Size& rhs) {
- return !(lhs == rhs);
-}
-
-#if !defined(COMPILER_MSVC)
-extern template class SizeBase<Size, int>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_SIZE_H_
diff --git a/chromium/ui/gfx/size_conversions.h b/chromium/ui/gfx/size_conversions.h
index af68195b55b..0ee67f417e8 100644
--- a/chromium/ui/gfx/size_conversions.h
+++ b/chromium/ui/gfx/size_conversions.h
@@ -1,24 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_SIZE_CONVERSIONS_H_
-#define UI_GFX_SIZE_CONVERSIONS_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/size_conversions.h"
-#include "ui/gfx/size.h"
-#include "ui/gfx/size_f.h"
-
-namespace gfx {
-
-// Returns a Size with each component from the input SizeF floored.
-GFX_EXPORT Size ToFlooredSize(const SizeF& size);
-
-// Returns a Size with each component from the input SizeF ceiled.
-GFX_EXPORT Size ToCeiledSize(const SizeF& size);
-
-// Returns a Size with each component from the input SizeF rounded.
-GFX_EXPORT Size ToRoundedSize(const SizeF& size);
-
-} // namespace gfx
-
-#endif // UI_GFX_SIZE_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/size_f.h b/chromium/ui/gfx/size_f.h
index b9065273c8e..0aabbcfcd53 100644
--- a/chromium/ui/gfx/size_f.h
+++ b/chromium/ui/gfx/size_f.h
@@ -1,54 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_SIZE_F_H_
-#define UI_GFX_SIZE_F_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/size_f.h"
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/size_base.h"
-
-namespace gfx {
-
-// A floating version of gfx::Size.
-class GFX_EXPORT SizeF : public SizeBase<SizeF, float> {
- public:
- SizeF() : SizeBase<SizeF, float>(0, 0) {}
- SizeF(float width, float height) : SizeBase<SizeF, float>(width, height) {}
- ~SizeF() {}
-
- void Scale(float scale) {
- Scale(scale, scale);
- }
-
- void Scale(float x_scale, float y_scale) {
- SetSize(width() * x_scale, height() * y_scale);
- }
-
- std::string ToString() const;
-};
-
-inline 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) {
- return !(lhs == rhs);
-}
-
-GFX_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);
-}
-
-#if !defined(COMPILER_MSVC)
-extern template class SizeBase<SizeF, float>;
-#endif
-
-} // namespace gfx
-
-#endif // UI_GFX_SIZE_F_H_
diff --git a/chromium/ui/gfx/skbitmap_operations.cc b/chromium/ui/gfx/skbitmap_operations.cc
index c89153692a4..d3b48271bbe 100644
--- a/chromium/ui/gfx/skbitmap_operations.cc
+++ b/chromium/ui/gfx/skbitmap_operations.cc
@@ -21,14 +21,12 @@
// static
SkBitmap SkBitmapOperations::CreateInvertedBitmap(const SkBitmap& image) {
- DCHECK(image.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(image.colorType() == kPMColor_SkColorType);
SkAutoLockPixels lock_image(image);
SkBitmap inverted;
- inverted.setConfig(SkBitmap::kARGB_8888_Config, image.width(), image.height(),
- 0);
- inverted.allocPixels();
+ inverted.allocN32Pixels(image.width(), image.height());
inverted.eraseARGB(0, 0, 0, 0);
for (int y = 0; y < image.height(); ++y) {
@@ -51,15 +49,13 @@ SkBitmap SkBitmapOperations::CreateSuperimposedBitmap(const SkBitmap& first,
DCHECK(first.width() == second.width());
DCHECK(first.height() == second.height());
DCHECK(first.bytesPerPixel() == second.bytesPerPixel());
- DCHECK(first.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(first.colorType() == kPMColor_SkColorType);
SkAutoLockPixels lock_first(first);
SkAutoLockPixels lock_second(second);
SkBitmap superimposed;
- superimposed.setConfig(SkBitmap::kARGB_8888_Config,
- first.width(), first.height());
- superimposed.allocPixels();
+ superimposed.allocN32Pixels(first.width(), first.height());
superimposed.eraseARGB(0, 0, 0, 0);
SkCanvas canvas(superimposed);
@@ -84,7 +80,7 @@ SkBitmap SkBitmapOperations::CreateBlendedBitmap(const SkBitmap& first,
DCHECK(first.width() == second.width());
DCHECK(first.height() == second.height());
DCHECK(first.bytesPerPixel() == second.bytesPerPixel());
- DCHECK(first.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(first.colorType() == kPMColor_SkColorType);
// Optimize for case where we won't need to blend anything.
static const double alpha_min = 1.0 / 255;
@@ -98,9 +94,7 @@ SkBitmap SkBitmapOperations::CreateBlendedBitmap(const SkBitmap& first,
SkAutoLockPixels lock_second(second);
SkBitmap blended;
- blended.setConfig(SkBitmap::kARGB_8888_Config, first.width(), first.height(),
- 0);
- blended.allocPixels();
+ blended.allocN32Pixels(first.width(), first.height());
blended.eraseARGB(0, 0, 0, 0);
double first_alpha = 1 - alpha;
@@ -136,12 +130,11 @@ SkBitmap SkBitmapOperations::CreateMaskedBitmap(const SkBitmap& rgb,
DCHECK(rgb.width() == alpha.width());
DCHECK(rgb.height() == alpha.height());
DCHECK(rgb.bytesPerPixel() == alpha.bytesPerPixel());
- DCHECK(rgb.config() == SkBitmap::kARGB_8888_Config);
- DCHECK(alpha.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(rgb.colorType() == kPMColor_SkColorType);
+ DCHECK(alpha.colorType() == kPMColor_SkColorType);
SkBitmap masked;
- masked.setConfig(SkBitmap::kARGB_8888_Config, rgb.width(), rgb.height(), 0);
- masked.allocPixels();
+ masked.allocN32Pixels(rgb.width(), rgb.height());
masked.eraseARGB(0, 0, 0, 0);
SkAutoLockPixels lock_rgb(rgb);
@@ -174,13 +167,11 @@ SkBitmap SkBitmapOperations::CreateMaskedBitmap(const SkBitmap& rgb,
SkBitmap SkBitmapOperations::CreateButtonBackground(SkColor color,
const SkBitmap& image,
const SkBitmap& mask) {
- DCHECK(image.config() == SkBitmap::kARGB_8888_Config);
- DCHECK(mask.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(image.colorType() == kPMColor_SkColorType);
+ DCHECK(mask.colorType() == kPMColor_SkColorType);
SkBitmap background;
- background.setConfig(
- SkBitmap::kARGB_8888_Config, mask.width(), mask.height(), 0);
- background.allocPixels();
+ background.allocN32Pixels(mask.width(), mask.height());
double bg_a = SkColorGetA(color);
double bg_r = SkColorGetR(color);
@@ -556,12 +547,10 @@ SkBitmap SkBitmapOperations::CreateHSLShiftedBitmap(
HSLShift::kLineProcessors[H_op][S_op][L_op];
DCHECK(bitmap.empty() == false);
- DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(bitmap.colorType() == kPMColor_SkColorType);
SkBitmap shifted;
- shifted.setConfig(SkBitmap::kARGB_8888_Config, bitmap.width(),
- bitmap.height());
- shifted.allocPixels();
+ shifted.allocN32Pixels(bitmap.width(), bitmap.height());
shifted.eraseARGB(0, 0, 0, 0);
SkAutoLockPixels lock_bitmap(bitmap);
@@ -582,11 +571,10 @@ SkBitmap SkBitmapOperations::CreateHSLShiftedBitmap(
SkBitmap SkBitmapOperations::CreateTiledBitmap(const SkBitmap& source,
int src_x, int src_y,
int dst_w, int dst_h) {
- DCHECK(source.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(source.colorType() == kPMColor_SkColorType);
SkBitmap cropped;
- cropped.setConfig(SkBitmap::kARGB_8888_Config, dst_w, dst_h, 0);
- cropped.allocPixels();
+ cropped.allocN32Pixels(dst_w, dst_h);
cropped.eraseARGB(0, 0, 0, 0);
SkAutoLockPixels lock_source(source);
@@ -635,9 +623,7 @@ SkBitmap SkBitmapOperations::DownsampleByTwo(const SkBitmap& bitmap) {
return bitmap;
SkBitmap result;
- result.setConfig(SkBitmap::kARGB_8888_Config,
- (bitmap.width() + 1) / 2, (bitmap.height() + 1) / 2);
- result.allocPixels();
+ result.allocN32Pixels((bitmap.width() + 1) / 2, (bitmap.height() + 1) / 2);
SkAutoLockPixels lock(bitmap);
@@ -702,10 +688,10 @@ SkBitmap SkBitmapOperations::UnPreMultiply(const SkBitmap& bitmap) {
if (bitmap.isOpaque())
return bitmap;
+ SkImageInfo info = bitmap.info();
+ info.fAlphaType = kOpaque_SkAlphaType;
SkBitmap opaque_bitmap;
- opaque_bitmap.setConfig(bitmap.config(), bitmap.width(), bitmap.height(),
- 0, kOpaque_SkAlphaType);
- opaque_bitmap.allocPixels();
+ opaque_bitmap.allocPixels(info);
{
SkAutoLockPixels bitmap_lock(bitmap);
@@ -725,12 +711,10 @@ SkBitmap SkBitmapOperations::UnPreMultiply(const SkBitmap& bitmap) {
// static
SkBitmap SkBitmapOperations::CreateTransposedBitmap(const SkBitmap& image) {
- DCHECK(image.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(image.colorType() == kPMColor_SkColorType);
SkBitmap transposed;
- transposed.setConfig(
- SkBitmap::kARGB_8888_Config, image.height(), image.width(), 0);
- transposed.allocPixels();
+ transposed.allocN32Pixels(image.height(), image.width());
SkAutoLockPixels lock_image(image);
SkAutoLockPixels lock_transposed(transposed);
@@ -749,12 +733,10 @@ SkBitmap SkBitmapOperations::CreateTransposedBitmap(const SkBitmap& image) {
// static
SkBitmap SkBitmapOperations::CreateColorMask(const SkBitmap& bitmap,
SkColor c) {
- DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(bitmap.colorType() == kPMColor_SkColorType);
SkBitmap color_mask;
- color_mask.setConfig(SkBitmap::kARGB_8888_Config,
- bitmap.width(), bitmap.height());
- color_mask.allocPixels();
+ color_mask.allocN32Pixels(bitmap.width(), bitmap.height());
color_mask.eraseARGB(0, 0, 0, 0);
SkCanvas canvas(color_mask);
@@ -771,7 +753,7 @@ SkBitmap SkBitmapOperations::CreateColorMask(const SkBitmap& bitmap,
SkBitmap SkBitmapOperations::CreateDropShadow(
const SkBitmap& bitmap,
const gfx::ShadowValues& shadows) {
- DCHECK(bitmap.config() == SkBitmap::kARGB_8888_Config);
+ DCHECK(bitmap.colorType() == kPMColor_SkColorType);
// Shadow margin insets are negative values because they grow outside.
// Negate them here as grow direction is not important and only pixel value
@@ -779,10 +761,8 @@ SkBitmap SkBitmapOperations::CreateDropShadow(
gfx::Insets shadow_margin = -gfx::ShadowValue::GetMargin(shadows);
SkBitmap image_with_shadow;
- image_with_shadow.setConfig(SkBitmap::kARGB_8888_Config,
- bitmap.width() + shadow_margin.width(),
- bitmap.height() + shadow_margin.height());
- image_with_shadow.allocPixels();
+ image_with_shadow.allocN32Pixels(bitmap.width() + shadow_margin.width(),
+ bitmap.height() + shadow_margin.height());
image_with_shadow.eraseARGB(0, 0, 0, 0);
SkCanvas canvas(image_with_shadow);
@@ -796,8 +776,8 @@ SkBitmap SkBitmapOperations::CreateDropShadow(
shadow.color());
skia::RefPtr<SkBlurImageFilter> filter =
- skia::AdoptRef(new SkBlurImageFilter(SkDoubleToScalar(shadow.blur()),
- SkDoubleToScalar(shadow.blur())));
+ skia::AdoptRef(SkBlurImageFilter::Create(
+ SkDoubleToScalar(shadow.blur()), SkDoubleToScalar(shadow.blur())));
paint.setImageFilter(filter.get());
canvas.saveLayer(0, &paint);
diff --git a/chromium/ui/gfx/skia_util.cc b/chromium/ui/gfx/skia_util.cc
index bb7cde7b4ba..0a991df20aa 100644
--- a/chromium/ui/gfx/skia_util.cc
+++ b/chromium/ui/gfx/skia_util.cc
@@ -64,13 +64,16 @@ void TransformToFlattenedSkMatrix(const gfx::Transform& transform,
skia::RefPtr<SkShader> CreateImageRepShader(const gfx::ImageSkiaRep& image_rep,
SkShader::TileMode tile_mode,
const SkMatrix& local_matrix) {
- skia::RefPtr<SkShader> shader = skia::AdoptRef(SkShader::CreateBitmapShader(
- image_rep.sk_bitmap(), tile_mode, tile_mode));
- SkScalar scale_x = local_matrix.getScaleX();
- SkScalar scale_y = local_matrix.getScaleY();
- SkScalar bitmap_scale = SkFloatToScalar(image_rep.scale());
+ return CreateImageRepShaderForScale(image_rep, tile_mode, local_matrix,
+ image_rep.scale());
+}
- // Unscale matrix by |bitmap_scale| such that the bitmap is drawn at the
+skia::RefPtr<SkShader> CreateImageRepShaderForScale(
+ const gfx::ImageSkiaRep& image_rep,
+ SkShader::TileMode tile_mode,
+ const SkMatrix& local_matrix,
+ SkScalar scale) {
+ // Unscale matrix by |scale| such that the bitmap is drawn at the
// correct density.
// Convert skew and translation to pixel coordinates.
// Thus, for |bitmap_scale| = 2:
@@ -78,11 +81,12 @@ skia::RefPtr<SkShader> CreateImageRepShader(const gfx::ImageSkiaRep& image_rep,
// should be converted to
// x scale = 1, x translation = 2 pixels.
SkMatrix shader_scale = local_matrix;
- shader_scale.preScale(bitmap_scale, bitmap_scale);
- shader_scale.setScaleX(SkScalarDiv(scale_x, bitmap_scale));
- shader_scale.setScaleY(SkScalarDiv(scale_y, bitmap_scale));
+ shader_scale.preScale(scale, scale);
+ shader_scale.setScaleX(local_matrix.getScaleX() / scale);
+ shader_scale.setScaleY(local_matrix.getScaleY() / scale);
- shader->setLocalMatrix(shader_scale);
+ skia::RefPtr<SkShader> shader = skia::AdoptRef(SkShader::CreateBitmapShader(
+ image_rep.sk_bitmap(), tile_mode, tile_mode, &shader_scale));
return shader;
}
@@ -99,15 +103,20 @@ skia::RefPtr<SkShader> CreateGradientShader(int start_point,
grad_points, grad_colors, NULL, 2, SkShader::kRepeat_TileMode));
}
+static SkScalar RadiusToSigma(double radius) {
+ // This captures historically what skia did under the hood. Now skia accepts
+ // sigma, not radius, so we perform the conversion.
+ return radius > 0 ? SkDoubleToScalar(0.57735f * radius + 0.5) : 0;
+}
+
skia::RefPtr<SkDrawLooper> CreateShadowDrawLooper(
const std::vector<ShadowValue>& shadows) {
if (shadows.empty())
return skia::RefPtr<SkDrawLooper>();
- skia::RefPtr<SkLayerDrawLooper> looper =
- skia::AdoptRef(new SkLayerDrawLooper);
+ SkLayerDrawLooper::Builder looper_builder;
- looper->addLayer(); // top layer of the original.
+ looper_builder.addLayer(); // top layer of the original.
SkLayerDrawLooper::LayerInfo layer_info;
layer_info.fPaintBits |= SkLayerDrawLooper::kMaskFilter_Bit;
@@ -123,19 +132,19 @@ skia::RefPtr<SkDrawLooper> CreateShadowDrawLooper(
// SkBlurMaskFilter's blur radius defines the range to extend the blur from
// original mask, which is half of blur amount as defined in ShadowValue.
skia::RefPtr<SkMaskFilter> blur_mask = skia::AdoptRef(
- SkBlurMaskFilter::Create(SkDoubleToScalar(shadow.blur() / 2),
- SkBlurMaskFilter::kNormal_BlurStyle,
+ SkBlurMaskFilter::Create(kNormal_SkBlurStyle,
+ RadiusToSigma(shadow.blur() / 2),
SkBlurMaskFilter::kHighQuality_BlurFlag));
skia::RefPtr<SkColorFilter> color_filter = skia::AdoptRef(
SkColorFilter::CreateModeFilter(shadow.color(),
SkXfermode::kSrcIn_Mode));
- SkPaint* paint = looper->addLayer(layer_info);
+ SkPaint* paint = looper_builder.addLayer(layer_info);
paint->setMaskFilter(blur_mask.get());
paint->setColorFilter(color_filter.get());
}
- return looper;
+ return skia::AdoptRef<SkDrawLooper>(looper_builder.detachLooper());
}
bool BitmapsAreEqual(const SkBitmap& bitmap1, const SkBitmap& bitmap2) {
diff --git a/chromium/ui/gfx/skia_util.h b/chromium/ui/gfx/skia_util.h
index 92c886a4309..0c759838b86 100644
--- a/chromium/ui/gfx/skia_util.h
+++ b/chromium/ui/gfx/skia_util.h
@@ -47,6 +47,13 @@ GFX_EXPORT skia::RefPtr<SkShader> CreateImageRepShader(
SkShader::TileMode tile_mode,
const SkMatrix& local_matrix);
+// Creates a bitmap shader for the image rep with the passed in scale factor.
+GFX_EXPORT skia::RefPtr<SkShader> CreateImageRepShaderForScale(
+ const gfx::ImageSkiaRep& image_rep,
+ SkShader::TileMode tile_mode,
+ const SkMatrix& local_matrix,
+ SkScalar scale);
+
// Creates a vertical gradient shader. The caller owns the shader.
// Example usage to avoid leaks:
GFX_EXPORT skia::RefPtr<SkShader> CreateGradientShader(int start_point,
diff --git a/chromium/ui/gfx/skia_utils_gtk.cc b/chromium/ui/gfx/skia_utils_gtk.cc
deleted file mode 100644
index f7f3a0aaf2b..00000000000
--- a/chromium/ui/gfx/skia_utils_gtk.cc
+++ /dev/null
@@ -1,32 +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 "ui/gfx/skia_utils_gtk.h"
-
-#include <gdk/gdk.h>
-
-namespace gfx {
-
-const int kSkiaToGDKMultiplier = 257;
-
-// GDK_COLOR_RGB multiplies by 257 (= 0x10001) to distribute the bits evenly
-// See: http://www.mindcontrol.org/~hplus/graphics/expand-bits.html
-// To get back, we can just right shift by eight
-// (or, formulated differently, i == (i*257)/256 for all i < 256).
-
-SkColor GdkColorToSkColor(GdkColor color) {
- return SkColorSetRGB(color.red >> 8, color.green >> 8, color.blue >> 8);
-}
-
-GdkColor SkColorToGdkColor(SkColor color) {
- GdkColor gdk_color = {
- 0,
- static_cast<guint16>(SkColorGetR(color) * kSkiaToGDKMultiplier),
- static_cast<guint16>(SkColorGetG(color) * kSkiaToGDKMultiplier),
- static_cast<guint16>(SkColorGetB(color) * kSkiaToGDKMultiplier)
- };
- return gdk_color;
-}
-
-} // namespace gfx
diff --git a/chromium/ui/gfx/skia_utils_gtk.h b/chromium/ui/gfx/skia_utils_gtk.h
deleted file mode 100644
index 6b74da246ea..00000000000
--- a/chromium/ui/gfx/skia_utils_gtk.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2011 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_UTILS_GTK_H_
-#define UI_GFX_SKIA_UTILS_GTK_H_
-
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/gfx_export.h"
-
-typedef struct _GdkColor GdkColor;
-
-namespace gfx {
-
-// Converts GdkColors to the ARGB layout Skia expects.
-GFX_EXPORT SkColor GdkColorToSkColor(GdkColor color);
-
-// Converts ARGB to GdkColor.
-GFX_EXPORT GdkColor SkColorToGdkColor(SkColor color);
-
-} // namespace gfx
-
-#endif // UI_GFX_SKIA_UTILS_GTK_H_
diff --git a/chromium/ui/gfx/skrect_conversion_unittest.cc b/chromium/ui/gfx/skrect_conversion_unittest.cc
new file mode 100644
index 00000000000..ef116c2a451
--- /dev/null
+++ b/chromium/ui/gfx/skrect_conversion_unittest.cc
@@ -0,0 +1,26 @@
+// 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 "base/basictypes.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/skia_util.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());
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/switches.cc b/chromium/ui/gfx/switches.cc
index 2f2eb9a3b82..2441a1483f5 100644
--- a/chromium/ui/gfx/switches.cc
+++ b/chromium/ui/gfx/switches.cc
@@ -6,11 +6,21 @@
namespace switches {
+// The ImageSkia looks up the resource pack with the closest available scale
+// factor instead of the actual device scale factor and then rescale on
+// ImageSkia side. This switch disables this feature.
+const char kDisableArbitraryScaleFactorInImageSkia[] =
+ "disable-arbitrary-scale-factor-in-image-skia";
+
// Let text glyphs have X-positions that aren't snapped to the pixel grid in
// the browser UI.
const char kEnableBrowserTextSubpixelPositioning[] =
"enable-browser-text-subpixel-positioning";
+// Uses the HarfBuzz port of RenderText on all platforms.
+const char kEnableHarfBuzzRenderText[] =
+ "enable-harfbuzz-rendertext";
+
// Enable text glyphs to have X-positions that aren't snapped to the pixel grid
// in webkit renderers.
const char kEnableWebkitTextSubpixelPositioning[] =
@@ -19,7 +29,4 @@ const char kEnableWebkitTextSubpixelPositioning[] =
// Overrides the device scale factor for the browser UI and the contents.
const char kForceDeviceScaleFactor[] = "force-device-scale-factor";
-// Enables/Disables High DPI support (windows)
-const char kHighDPISupport[] = "high-dpi-support";
-
} // namespace switches
diff --git a/chromium/ui/gfx/switches.h b/chromium/ui/gfx/switches.h
index c5629f249c4..1b6e10b7560 100644
--- a/chromium/ui/gfx/switches.h
+++ b/chromium/ui/gfx/switches.h
@@ -9,10 +9,12 @@
namespace switches {
+GFX_EXPORT extern const char kAllowArbitraryScaleFactorInImageSkia[];
+GFX_EXPORT extern const char kDisableArbitraryScaleFactorInImageSkia[];
GFX_EXPORT extern const char kEnableBrowserTextSubpixelPositioning[];
+GFX_EXPORT extern const char kEnableHarfBuzzRenderText[];
GFX_EXPORT extern const char kEnableWebkitTextSubpixelPositioning[];
GFX_EXPORT extern const char kForceDeviceScaleFactor[];
-GFX_EXPORT extern const char kHighDPISupport[];
} // namespace switches
diff --git a/chromium/ui/gfx/sys_color_change_listener.cc b/chromium/ui/gfx/sys_color_change_listener.cc
index d5646b3a81c..4a394aea5ee 100644
--- a/chromium/ui/gfx/sys_color_change_listener.cc
+++ b/chromium/ui/gfx/sys_color_change_listener.cc
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "ui/gfx/color_utils.h"
#include "ui/gfx/sys_color_change_listener.h"
#if defined(OS_WIN)
@@ -12,6 +11,8 @@
#include "base/basictypes.h"
#include "base/memory/singleton.h"
#include "base/observer_list.h"
+#include "ui/gfx/color_utils.h"
+
#if defined(OS_WIN)
#include "ui/gfx/win/singleton_hwnd.h"
#endif
diff --git a/chromium/ui/gfx/text_constants.h b/chromium/ui/gfx/text_constants.h
index 4ac788e6109..47c91cf5f14 100644
--- a/chromium/ui/gfx/text_constants.h
+++ b/chromium/ui/gfx/text_constants.h
@@ -10,34 +10,25 @@ namespace gfx {
// TODO(msw): Distinguish between logical character stops and glyph stops?
// TODO(msw): Merge with base::i18n::BreakIterator::BreakType.
enum BreakType {
- // Stop cursor movement on neighboring characters.
- CHARACTER_BREAK = 0,
- // Stop cursor movement on nearest word boundaries.
- WORD_BREAK,
- // Stop cursor movement on line ends as shown on screen.
- LINE_BREAK,
+ CHARACTER_BREAK = 0, // Stop cursor movement on neighboring characters.
+ WORD_BREAK, // Stop cursor movement on nearest word boundaries.
+ LINE_BREAK, // Stop cursor movement on line ends as shown on screen.
};
// Horizontal text alignment modes.
enum HorizontalAlignment {
- // Align the text's left edge with that of its display area.
- ALIGN_LEFT = 0,
- // Align the text's center with that of its display area.
- ALIGN_CENTER,
- // Align the text's right edge with that of its display area.
- ALIGN_RIGHT,
+ ALIGN_LEFT = 0, // Align the text's left edge with that of its display area.
+ ALIGN_CENTER, // Align the text's center with that of its display area.
+ ALIGN_RIGHT, // Align the text's right edge with that of its display area.
+ ALIGN_TO_HEAD, // Align the text to its first strong character's direction.
};
// The directionality modes used to determine the base text direction.
enum DirectionalityMode {
- // Use the first strong character's direction.
- DIRECTIONALITY_FROM_TEXT = 0,
- // Use the UI locale's text reading direction.
- DIRECTIONALITY_FROM_UI,
- // Use LTR regardless of content or UI locale.
- DIRECTIONALITY_FORCE_LTR,
- // Use RTL regardless of content or UI locale.
- DIRECTIONALITY_FORCE_RTL,
+ DIRECTIONALITY_FROM_TEXT = 0, // Use the first strong character's direction.
+ DIRECTIONALITY_FROM_UI, // Use the UI locale's text reading direction.
+ DIRECTIONALITY_FORCE_LTR, // Use LTR regardless of content or UI locale.
+ DIRECTIONALITY_FORCE_RTL, // Use RTL regardless of content or UI locale.
};
// Text styles and adornments.
@@ -51,6 +42,16 @@ enum TextStyle {
NUM_TEXT_STYLES,
};
+// Elision behaviors of text that exceeds constrained dimensions.
+enum ElideBehavior {
+ TRUNCATE = 0, // Do not elide or fade; the text may be truncated at the end.
+ ELIDE_HEAD, // Add an ellipsis at the start of the string.
+ ELIDE_MIDDLE, // Add an ellipsis in the middle of the string.
+ ELIDE_TAIL, // Add an ellipsis at the end of the string.
+ ELIDE_EMAIL, // Add ellipses to username and domain substrings.
+ FADE_TAIL, // Fade the string's end opposite of its horizontal alignment.
+};
+
} // namespace gfx
#endif // UI_GFX_TEXT_CONSTANTS_H_
diff --git a/chromium/ui/gfx/text_elider.cc b/chromium/ui/gfx/text_elider.cc
index 5b9469614f2..8c07bdecd5f 100644
--- a/chromium/ui/gfx/text_elider.cc
+++ b/chromium/ui/gfx/text_elider.cc
@@ -21,135 +21,29 @@
#include "base/strings/string_util.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
-#include "net/base/escape.h"
-#include "net/base/net_util.h"
-#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "third_party/icu/source/common/unicode/rbbi.h"
#include "third_party/icu/source/common/unicode/uloc.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/text_utils.h"
-#include "url/gurl.h"
-namespace gfx {
+using base::ASCIIToUTF16;
+using base::UTF8ToUTF16;
+using base::WideToUTF16;
-// U+2026 in utf8
-const char kEllipsis[] = "\xE2\x80\xA6";
-const base::char16 kEllipsisUTF16[] = { 0x2026, 0 };
-const base::char16 kForwardSlash = '/';
+namespace gfx {
namespace {
-// Helper class to split + elide text, while respecting UTF16 surrogate pairs.
-class StringSlicer {
- public:
- StringSlicer(const base::string16& text,
- const base::string16& ellipsis,
- bool elide_in_middle)
- : text_(text),
- ellipsis_(ellipsis),
- elide_in_middle_(elide_in_middle) {
- }
-
- // Cuts |text_| to be |length| characters long. If |elide_in_middle_| is true,
- // the middle of the string is removed to leave equal-length pieces from the
- // beginning and end of the string; otherwise, the end of the string is
- // removed and only the beginning remains. If |insert_ellipsis| is true,
- // then an ellipsis character will be inserted at the cut point.
- base::string16 CutString(size_t length, bool insert_ellipsis) {
- const base::string16 ellipsis_text = insert_ellipsis ? ellipsis_
- : base::string16();
-
- if (!elide_in_middle_)
- return text_.substr(0, FindValidBoundaryBefore(length)) + ellipsis_text;
-
- // We put the extra character, if any, before the cut.
- const size_t half_length = length / 2;
- const size_t prefix_length = FindValidBoundaryBefore(length - half_length);
- const size_t suffix_start_guess = text_.length() - half_length;
- const size_t suffix_start = FindValidBoundaryAfter(suffix_start_guess);
- const size_t suffix_length =
- half_length - (suffix_start_guess - suffix_start);
- return text_.substr(0, prefix_length) + ellipsis_text +
- text_.substr(suffix_start, suffix_length);
- }
-
- private:
- // Returns a valid cut boundary at or before |index|.
- size_t FindValidBoundaryBefore(size_t index) const {
- DCHECK_LE(index, text_.length());
- if (index != text_.length())
- U16_SET_CP_START(text_.data(), 0, index);
- return index;
- }
-
- // Returns a valid cut boundary at or after |index|.
- size_t FindValidBoundaryAfter(size_t index) const {
- DCHECK_LE(index, text_.length());
- if (index != text_.length())
- U16_SET_CP_LIMIT(text_.data(), 0, index, text_.length());
- return index;
- }
-
- // The text to be sliced.
- const base::string16& text_;
-
- // Ellipsis string to use.
- const base::string16& ellipsis_;
-
- // If true, the middle of the string will be elided.
- bool elide_in_middle_;
-
- DISALLOW_COPY_AND_ASSIGN(StringSlicer);
-};
-
-// Build a path from the first |num_components| elements in |path_elements|.
-// Prepends |path_prefix|, appends |filename|, inserts ellipsis if appropriate.
-base::string16 BuildPathFromComponents(
- const base::string16& path_prefix,
- const std::vector<base::string16>& path_elements,
- const base::string16& filename,
- size_t num_components) {
- // Add the initial elements of the path.
- base::string16 path = path_prefix;
-
- // Build path from first |num_components| elements.
- for (size_t j = 0; j < num_components; ++j)
- path += path_elements[j] + kForwardSlash;
-
- // Add |filename|, ellipsis if necessary.
- if (num_components != (path_elements.size() - 1))
- path += base::string16(kEllipsisUTF16) + kForwardSlash;
- path += filename;
-
- return path;
-}
-
-// Takes a prefix (Domain, or Domain+subdomain) and a collection of path
-// components and elides if possible. Returns a string containing the longest
-// possible elided path, or an empty string if elision is not possible.
-base::string16 ElideComponentizedPath(
- const base::string16& url_path_prefix,
- const std::vector<base::string16>& url_path_elements,
- const base::string16& url_filename,
- const base::string16& url_query,
- const FontList& font_list,
- float available_pixel_width) {
- const size_t url_path_number_of_elements = url_path_elements.size();
-
- CHECK(url_path_number_of_elements);
- for (size_t i = url_path_number_of_elements - 1; i > 0; --i) {
- base::string16 elided_path = BuildPathFromComponents(url_path_prefix,
- url_path_elements, url_filename, i);
- if (available_pixel_width >= GetStringWidthF(elided_path, font_list))
- return ElideText(elided_path + url_query, font_list,
- available_pixel_width, ELIDE_AT_END);
- }
-
- return base::string16();
-}
-
-} // namespace
-
+// Elides a well-formed email address (e.g. username@domain.com) to fit into
+// |available_pixel_width| using the specified |font_list|.
+// This function guarantees that the string returned will contain at least one
+// character, other than the ellipses, on either side of the '@'. If it is
+// impossible to achieve these requirements: only an ellipsis will be returned.
+// If possible: this elides only the username portion of the |email|. Otherwise,
+// the domain is elided in the middle so that it splits the available width
+// equally with the elided username (should the username be short enough that it
+// doesn't need half the available width: the elided domain will occupy that
+// extra width).
base::string16 ElideEmail(const base::string16& email,
const FontList& font_list,
float available_pixel_width) {
@@ -191,8 +85,7 @@ base::string16 ElideEmail(const base::string16& email,
std::min(available_domain_width,
std::max(available_pixel_width - full_username_width,
available_pixel_width / 2));
- domain = ElideText(domain, font_list, desired_domain_width,
- ELIDE_IN_MIDDLE);
+ domain = ElideText(domain, font_list, desired_domain_width, ELIDE_MIDDLE);
// Failing to elide the domain such that at least one character remains
// (other than the ellipsis itself) remains: return a single ellipsis.
if (domain.length() <= 1U)
@@ -203,206 +96,61 @@ base::string16 ElideEmail(const base::string16& email,
// is guaranteed to fit with at least one character remaining given all the
// precautions taken earlier).
available_pixel_width -= GetStringWidthF(domain, font_list);
- username = ElideText(username, font_list, available_pixel_width,
- ELIDE_AT_END);
-
+ username = ElideText(username, font_list, available_pixel_width, ELIDE_TAIL);
return username + kAtSignUTF16 + domain;
}
-// TODO(pkasting): http://crbug.com/77883 This whole function gets
-// kerning/ligatures/etc. issues potentially wrong by assuming that the width of
-// a rendered string is always the sum of the widths of its substrings. Also I
-// suspect it could be made simpler.
-base::string16 ElideUrl(const GURL& url,
- const FontList& font_list,
- float available_pixel_width,
- const std::string& languages) {
- // Get a formatted string and corresponding parsing of the url.
- url_parse::Parsed parsed;
- const base::string16 url_string =
- net::FormatUrl(url, languages, net::kFormatUrlOmitAll,
- net::UnescapeRule::SPACES, &parsed, NULL, NULL);
- if (available_pixel_width <= 0)
- return url_string;
-
- // If non-standard, return plain eliding.
- if (!url.IsStandard())
- return ElideText(url_string, font_list, available_pixel_width,
- ELIDE_AT_END);
-
- // Now start eliding url_string to fit within available pixel width.
- // Fist pass - check to see whether entire url_string fits.
- const float pixel_width_url_string = GetStringWidthF(url_string, font_list);
- if (available_pixel_width >= pixel_width_url_string)
- return url_string;
-
- // Get the path substring, including query and reference.
- const size_t path_start_index = parsed.path.begin;
- const size_t path_len = parsed.path.len;
- base::string16 url_path_query_etc = url_string.substr(path_start_index);
- base::string16 url_path = url_string.substr(path_start_index, path_len);
-
- // Return general elided text if url minus the query fits.
- const base::string16 url_minus_query =
- url_string.substr(0, path_start_index + path_len);
- if (available_pixel_width >= GetStringWidthF(url_minus_query, font_list))
- return ElideText(url_string, font_list, available_pixel_width,
- ELIDE_AT_END);
-
- // Get Host.
- base::string16 url_host = UTF8ToUTF16(url.host());
-
- // Get domain and registry information from the URL.
- base::string16 url_domain = UTF8ToUTF16(
- net::registry_controlled_domains::GetDomainAndRegistry(
- url, net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES));
- if (url_domain.empty())
- url_domain = url_host;
-
- // Add port if required.
- if (!url.port().empty()) {
- url_host += UTF8ToUTF16(":" + url.port());
- url_domain += UTF8ToUTF16(":" + url.port());
- }
-
- // Get sub domain.
- base::string16 url_subdomain;
- const size_t domain_start_index = url_host.find(url_domain);
- if (domain_start_index != base::string16::npos)
- url_subdomain = url_host.substr(0, domain_start_index);
- const base::string16 kWwwPrefix = UTF8ToUTF16("www.");
- if ((url_subdomain == kWwwPrefix || url_subdomain.empty() ||
- url.SchemeIsFile())) {
- url_subdomain.clear();
- }
-
- // If this is a file type, the path is now defined as everything after ":".
- // For example, "C:/aa/aa/bb", the path is "/aa/bb/cc". Interesting, the
- // domain is now C: - this is a nice hack for eliding to work pleasantly.
- if (url.SchemeIsFile()) {
- // Split the path string using ":"
- std::vector<base::string16> file_path_split;
- base::SplitString(url_path, ':', &file_path_split);
- if (file_path_split.size() > 1) { // File is of type "file:///C:/.."
- url_host.clear();
- url_domain.clear();
- url_subdomain.clear();
-
- const base::string16 kColon = UTF8ToUTF16(":");
- url_host = url_domain = file_path_split.at(0).substr(1) + kColon;
- url_path_query_etc = url_path = file_path_split.at(1);
- }
- }
+} // namespace
- // Second Pass - remove scheme - the rest fits.
- const float pixel_width_url_host = GetStringWidthF(url_host, font_list);
- const float pixel_width_url_path = GetStringWidthF(url_path_query_etc,
- font_list);
- if (available_pixel_width >=
- pixel_width_url_host + pixel_width_url_path)
- return url_host + url_path_query_etc;
-
- // Third Pass: Subdomain, domain and entire path fits.
- const float pixel_width_url_domain = GetStringWidthF(url_domain, font_list);
- const float pixel_width_url_subdomain =
- GetStringWidthF(url_subdomain, font_list);
- if (available_pixel_width >=
- pixel_width_url_subdomain + pixel_width_url_domain +
- pixel_width_url_path)
- return url_subdomain + url_domain + url_path_query_etc;
-
- // Query element.
- base::string16 url_query;
- const float kPixelWidthDotsTrailer = GetStringWidthF(
- base::string16(kEllipsisUTF16), font_list);
- if (parsed.query.is_nonempty()) {
- url_query = UTF8ToUTF16("?") + url_string.substr(parsed.query.begin);
- if (available_pixel_width >=
- (pixel_width_url_subdomain + pixel_width_url_domain +
- pixel_width_url_path - GetStringWidthF(url_query, font_list))) {
- return ElideText(url_subdomain + url_domain + url_path_query_etc,
- font_list, available_pixel_width, ELIDE_AT_END);
- }
- }
+// U+2026 in utf8
+const char kEllipsis[] = "\xE2\x80\xA6";
+const base::char16 kEllipsisUTF16[] = { 0x2026, 0 };
+const base::char16 kForwardSlash = '/';
- // Parse url_path using '/'.
- std::vector<base::string16> url_path_elements;
- base::SplitString(url_path, kForwardSlash, &url_path_elements);
-
- // Get filename - note that for a path ending with /
- // such as www.google.com/intl/ads/, the file name is ads/.
- size_t url_path_number_of_elements = url_path_elements.size();
- DCHECK(url_path_number_of_elements != 0);
- base::string16 url_filename;
- if ((url_path_elements.at(url_path_number_of_elements - 1)).length() > 0) {
- url_filename = *(url_path_elements.end() - 1);
- } else if (url_path_number_of_elements > 1) { // Path ends with a '/'.
- url_filename = url_path_elements.at(url_path_number_of_elements - 2) +
- kForwardSlash;
- url_path_number_of_elements--;
- }
- DCHECK(url_path_number_of_elements != 0);
-
- const size_t kMaxNumberOfUrlPathElementsAllowed = 1024;
- if (url_path_number_of_elements <= 1 ||
- url_path_number_of_elements > kMaxNumberOfUrlPathElementsAllowed) {
- // No path to elide, or too long of a path (could overflow in loop below)
- // Just elide this as a text string.
- return ElideText(url_subdomain + url_domain + url_path_query_etc, font_list,
- available_pixel_width, ELIDE_AT_END);
- }
+StringSlicer::StringSlicer(const base::string16& text,
+ const base::string16& ellipsis,
+ bool elide_in_middle,
+ bool elide_at_beginning)
+ : text_(text),
+ ellipsis_(ellipsis),
+ elide_in_middle_(elide_in_middle),
+ elide_at_beginning_(elide_at_beginning) {
+}
- // Start eliding the path and replacing elements by ".../".
- const base::string16 kEllipsisAndSlash =
- base::string16(kEllipsisUTF16) + kForwardSlash;
- const float pixel_width_ellipsis_slash =
- GetStringWidthF(kEllipsisAndSlash, font_list);
-
- // Check with both subdomain and domain.
- base::string16 elided_path =
- ElideComponentizedPath(url_subdomain + url_domain, url_path_elements,
- url_filename, url_query, font_list,
- available_pixel_width);
- if (!elided_path.empty())
- return elided_path;
-
- // Check with only domain.
- // If a subdomain is present, add an ellipsis before domain.
- // This is added only if the subdomain pixel width is larger than
- // the pixel width of kEllipsis. Otherwise, subdomain remains,
- // which means that this case has been resolved earlier.
- base::string16 url_elided_domain = url_subdomain + url_domain;
- if (pixel_width_url_subdomain > kPixelWidthDotsTrailer) {
- if (!url_subdomain.empty())
- url_elided_domain = kEllipsisAndSlash[0] + url_domain;
- else
- url_elided_domain = url_domain;
-
- elided_path = ElideComponentizedPath(url_elided_domain, url_path_elements,
- url_filename, url_query, font_list,
- available_pixel_width);
-
- if (!elided_path.empty())
- return elided_path;
- }
+base::string16 StringSlicer::CutString(size_t length, bool insert_ellipsis) {
+ const base::string16 ellipsis_text = insert_ellipsis ? ellipsis_
+ : base::string16();
+
+ if (elide_at_beginning_)
+ return ellipsis_text +
+ text_.substr(FindValidBoundaryBefore(text_.length() - length));
+
+ if (!elide_in_middle_)
+ return text_.substr(0, FindValidBoundaryBefore(length)) + ellipsis_text;
+
+ // We put the extra character, if any, before the cut.
+ const size_t half_length = length / 2;
+ const size_t prefix_length = FindValidBoundaryBefore(length - half_length);
+ const size_t suffix_start_guess = text_.length() - half_length;
+ const size_t suffix_start = FindValidBoundaryAfter(suffix_start_guess);
+ const size_t suffix_length =
+ half_length - (suffix_start_guess - suffix_start);
+ return text_.substr(0, prefix_length) + ellipsis_text +
+ text_.substr(suffix_start, suffix_length);
+}
- // Return elided domain/.../filename anyway.
- base::string16 final_elided_url_string(url_elided_domain);
- const float url_elided_domain_width = GetStringWidthF(url_elided_domain,
- font_list);
-
- // A hack to prevent trailing ".../...".
- if ((available_pixel_width - url_elided_domain_width) >
- pixel_width_ellipsis_slash + kPixelWidthDotsTrailer +
- GetStringWidthF(ASCIIToUTF16("UV"), font_list)) {
- final_elided_url_string += BuildPathFromComponents(base::string16(),
- url_path_elements, url_filename, 1);
- } else {
- final_elided_url_string += url_path;
- }
+size_t StringSlicer::FindValidBoundaryBefore(size_t index) const {
+ DCHECK_LE(index, text_.length());
+ if (index != text_.length())
+ U16_SET_CP_START(text_.data(), 0, index);
+ return index;
+}
- return ElideText(final_elided_url_string, font_list, available_pixel_width,
- ELIDE_AT_END);
+size_t StringSlicer::FindValidBoundaryAfter(size_t index) const {
+ DCHECK_LE(index, text_.length());
+ if (index != text_.length())
+ U16_SET_CP_LIMIT(text_.data(), 0, index, text_.length());
+ return index;
}
base::string16 ElideFilename(const base::FilePath& filename,
@@ -426,8 +174,8 @@ base::string16 ElideFilename(const base::FilePath& filename,
return base::i18n::GetDisplayStringInLTRDirectionality(filename_utf16);
if (rootname.empty() || extension.empty()) {
- const base::string16 elided_name = ElideText(filename_utf16, font_list,
- available_pixel_width, ELIDE_AT_END);
+ const base::string16 elided_name =
+ ElideText(filename_utf16, font_list, available_pixel_width, ELIDE_TAIL);
return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
}
@@ -442,14 +190,13 @@ base::string16 ElideFilename(const base::FilePath& filename,
if (ext_width >= available_pixel_width) {
const base::string16 elided_name = ElideText(
- rootname + extension, font_list, available_pixel_width,
- ELIDE_IN_MIDDLE);
+ rootname + extension, font_list, available_pixel_width, ELIDE_MIDDLE);
return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
}
float available_root_width = available_pixel_width - ext_width;
base::string16 elided_name =
- ElideText(rootname, font_list, available_root_width, ELIDE_AT_END);
+ ElideText(rootname, font_list, available_root_width, ELIDE_TAIL);
elided_name += extension;
return base::i18n::GetDisplayStringInLTRDirectionality(elided_name);
}
@@ -457,16 +204,19 @@ base::string16 ElideFilename(const base::FilePath& filename,
base::string16 ElideText(const base::string16& text,
const FontList& font_list,
float available_pixel_width,
- ElideBehavior elide_behavior) {
- if (text.empty())
+ ElideBehavior behavior) {
+ DCHECK_NE(behavior, FADE_TAIL);
+ if (text.empty() || behavior == FADE_TAIL)
return text;
+ if (behavior == ELIDE_EMAIL)
+ return ElideEmail(text, font_list, available_pixel_width);
const float current_text_pixel_width = GetStringWidthF(text, font_list);
- const bool elide_in_middle = (elide_behavior == ELIDE_IN_MIDDLE);
- const bool insert_ellipsis = (elide_behavior != TRUNCATE_AT_END);
-
+ const bool elide_in_middle = (behavior == ELIDE_MIDDLE);
+ const bool elide_at_beginning = (behavior == ELIDE_HEAD);
+ const bool insert_ellipsis = (behavior != TRUNCATE);
const base::string16 ellipsis = base::string16(kEllipsisUTF16);
- StringSlicer slicer(text, ellipsis, elide_in_middle);
+ StringSlicer slicer(text, ellipsis, elide_in_middle, elide_at_beginning);
// Pango will return 0 width for absurdly long strings. Cut the string in
// half and try again.
@@ -476,9 +226,10 @@ base::string16 ElideText(const base::string16& text,
// return positive numbers again. Detecting that is probably not worth it
// (eliding way too much from a ridiculous string is probably still
// ridiculous), but we should check other widths for bogus values as well.
- if (current_text_pixel_width <= 0 && !text.empty()) {
- const base::string16 cut = slicer.CutString(text.length() / 2, false);
- return ElideText(cut, font_list, available_pixel_width, elide_behavior);
+ if (current_text_pixel_width <= 0) {
+ const base::string16 cut =
+ slicer.CutString(text.length() / 2, insert_ellipsis);
+ return ElideText(cut, font_list, available_pixel_width, behavior);
}
if (current_text_pixel_width <= available_pixel_width)
@@ -493,103 +244,30 @@ base::string16 ElideText(const base::string16& text,
size_t hi = text.length() - 1;
size_t guess;
for (guess = (lo + hi) / 2; lo <= hi; guess = (lo + hi) / 2) {
- // We check the length of the whole desired string at once to ensure we
+ // We check the width of the whole desired string at once to ensure we
// handle kerning/ligatures/etc. correctly.
+ // TODO(skanuj) : Handle directionality of ellipsis based on adjacent
+ // characters. See crbug.com/327963.
const base::string16 cut = slicer.CutString(guess, insert_ellipsis);
- const float guess_length = GetStringWidthF(cut, font_list);
- // Check again that we didn't hit a Pango width overflow. If so, cut the
- // current string in half and start over.
- if (guess_length <= 0) {
- return ElideText(slicer.CutString(guess / 2, false),
- font_list, available_pixel_width, elide_behavior);
- }
- if (guess_length > available_pixel_width)
+ const float guess_width = GetStringWidthF(cut, font_list);
+ if (guess_width == available_pixel_width)
+ break;
+ if (guess_width > available_pixel_width) {
hi = guess - 1;
- else
+ // Move back if we are on loop terminating condition, and guess is wider
+ // than available.
+ if (hi < lo)
+ lo = hi;
+ } else {
lo = guess + 1;
+ }
}
return slicer.CutString(guess, insert_ellipsis);
}
-base::string16 ElideText(const base::string16& text,
- const Font& font,
- float available_pixel_width,
- ElideBehavior elide_behavior) {
- return ElideText(text, FontList(font), available_pixel_width, elide_behavior);
-}
-
-SortedDisplayURL::SortedDisplayURL(const GURL& url,
- const std::string& languages) {
- net::AppendFormattedHost(url, languages, &sort_host_);
- base::string16 host_minus_www = net::StripWWW(sort_host_);
- url_parse::Parsed parsed;
- display_url_ =
- net::FormatUrl(url, languages, net::kFormatUrlOmitAll,
- net::UnescapeRule::SPACES, &parsed, &prefix_end_, NULL);
- if (sort_host_.length() > host_minus_www.length()) {
- prefix_end_ += sort_host_.length() - host_minus_www.length();
- sort_host_.swap(host_minus_www);
- }
-}
-
-SortedDisplayURL::SortedDisplayURL() : prefix_end_(0) {
-}
-
-SortedDisplayURL::~SortedDisplayURL() {
-}
-
-int SortedDisplayURL::Compare(const SortedDisplayURL& other,
- icu::Collator* collator) const {
- // Compare on hosts first. The host won't contain 'www.'.
- UErrorCode compare_status = U_ZERO_ERROR;
- UCollationResult host_compare_result = collator->compare(
- static_cast<const UChar*>(sort_host_.c_str()),
- static_cast<int>(sort_host_.length()),
- static_cast<const UChar*>(other.sort_host_.c_str()),
- static_cast<int>(other.sort_host_.length()),
- compare_status);
- DCHECK(U_SUCCESS(compare_status));
- if (host_compare_result != 0)
- return host_compare_result;
-
- // Hosts match, compare on the portion of the url after the host.
- base::string16 path = this->AfterHost();
- base::string16 o_path = other.AfterHost();
- compare_status = U_ZERO_ERROR;
- UCollationResult path_compare_result = collator->compare(
- static_cast<const UChar*>(path.c_str()),
- static_cast<int>(path.length()),
- static_cast<const UChar*>(o_path.c_str()),
- static_cast<int>(o_path.length()),
- compare_status);
- DCHECK(U_SUCCESS(compare_status));
- if (path_compare_result != 0)
- return path_compare_result;
-
- // Hosts and paths match, compare on the complete url. This'll push the www.
- // ones to the end.
- compare_status = U_ZERO_ERROR;
- UCollationResult display_url_compare_result = collator->compare(
- static_cast<const UChar*>(display_url_.c_str()),
- static_cast<int>(display_url_.length()),
- static_cast<const UChar*>(other.display_url_.c_str()),
- static_cast<int>(other.display_url_.length()),
- compare_status);
- DCHECK(U_SUCCESS(compare_status));
- return display_url_compare_result;
-}
-
-base::string16 SortedDisplayURL::AfterHost() const {
- const size_t slash_index = display_url_.find(sort_host_, prefix_end_);
- if (slash_index == base::string16::npos) {
- NOTREACHED();
- return base::string16();
- }
- return display_url_.substr(slash_index + sort_host_.length());
-}
-
-bool ElideString(const base::string16& input, int max_len,
+bool ElideString(const base::string16& input,
+ int max_len,
base::string16* output) {
DCHECK_GE(max_len, 0);
if (static_cast<int>(input.length()) <= max_len) {
@@ -915,7 +593,7 @@ int RectangleText::Finalize() {
// Remove trailing whitespace from the last line or remove the last line
// completely, if it's just whitespace.
if (!insufficient_height_ && !lines_->empty()) {
- TrimWhitespace(lines_->back(), TRIM_TRAILING, &lines_->back());
+ base::TrimWhitespace(lines_->back(), base::TRIM_TRAILING, &lines_->back());
if (lines_->back().empty() && !last_line_ended_in_lf_)
lines_->pop_back();
}
@@ -943,9 +621,10 @@ void RectangleText::AddLine(const base::string16& line) {
if (truncate) {
// Trim trailing whitespace from the line that was added.
const int line = lines_->size() - lines_added;
- TrimWhitespace(lines_->at(line), TRIM_TRAILING, &lines_->at(line));
+ base::TrimWhitespace(lines_->at(line), base::TRIM_TRAILING,
+ &lines_->at(line));
}
- if (ContainsOnlyWhitespace(word)) {
+ if (base::ContainsOnlyChars(word, base::kWhitespaceUTF16)) {
// Skip the first space if the previous line was carried over.
current_width_ = 0;
current_line_.clear();
@@ -967,11 +646,10 @@ int RectangleText::WrapWord(const base::string16& word) {
bool first_fragment = true;
while (!insufficient_height_ && !text.empty()) {
base::string16 fragment =
- ElideText(text, font_list_, available_pixel_width_,
- TRUNCATE_AT_END);
+ 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())
+ if (fragment.empty())
fragment = text.substr(0, 1);
if (!first_fragment && NewLine())
lines_added++;
@@ -999,7 +677,7 @@ int RectangleText::AddWordOverflow(const base::string16& word) {
lines_added += WrapWord(word);
} else {
const ElideBehavior elide_behavior =
- (wrap_behavior_ == ELIDE_LONG_WORDS ? ELIDE_AT_END : TRUNCATE_AT_END);
+ (wrap_behavior_ == ELIDE_LONG_WORDS ? ELIDE_TAIL : TRUNCATE);
const base::string16 elided_word =
ElideText(word, font_list_, available_pixel_width_, elide_behavior);
AddToCurrentLine(elided_word);
@@ -1012,7 +690,7 @@ int RectangleText::AddWordOverflow(const base::string16& word) {
int RectangleText::AddWord(const base::string16& word) {
int lines_added = 0;
base::string16 trimmed;
- TrimWhitespace(word, TRIM_TRAILING, &trimmed);
+ base::TrimWhitespace(word, base::TRIM_TRAILING, &trimmed);
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.
diff --git a/chromium/ui/gfx/text_elider.h b/chromium/ui/gfx/text_elider.h
index 4eaca828c7d..a416fda779e 100644
--- a/chromium/ui/gfx/text_elider.h
+++ b/chromium/ui/gfx/text_elider.h
@@ -12,9 +12,8 @@
#include "base/basictypes.h"
#include "base/strings/string16.h"
-#include "third_party/icu/source/common/unicode/uchar.h"
-#include "third_party/icu/source/i18n/unicode/coll.h"
#include "ui/gfx/gfx_export.h"
+#include "ui/gfx/text_constants.h"
class GURL;
@@ -23,65 +22,52 @@ class FilePath;
}
namespace gfx {
-class Font;
class FontList;
GFX_EXPORT extern const char kEllipsis[];
GFX_EXPORT extern const base::char16 kEllipsisUTF16[];
+GFX_EXPORT extern const base::char16 kForwardSlash;
-// Elides a well-formed email address (e.g. username@domain.com) to fit into
-// |available_pixel_width| using the specified |font_list|.
-// This function guarantees that the string returned will contain at least one
-// character, other than the ellipses, on either side of the '@'. If it is
-// impossible to achieve these requirements: only an ellipsis will be returned.
-// If possible: this elides only the username portion of the |email|. Otherwise,
-// the domain is elided in the middle so that it splits the available width
-// equally with the elided username (should the username be short enough that it
-// doesn't need half the available width: the elided domain will occupy that
-// extra width).
-GFX_EXPORT base::string16 ElideEmail(const base::string16& email,
- const gfx::FontList& font_list,
- float available_pixel_width);
-
-// This function takes a GURL object and elides it. It returns a string
-// which composed of parts from subdomain, domain, path, filename and query.
-// A "..." is added automatically at the end if the elided string is bigger
-// than the |available_pixel_width|. For |available_pixel_width| == 0, a
-// formatted, but un-elided, string is returned. |languages| is a comma
-// separated list of ISO 639 language codes and is used to determine what
-// characters are understood by a user. It should come from
-// |prefs::kAcceptLanguages|.
-//
-// Note: in RTL locales, if the URL returned by this function is going to be
-// displayed in the UI, then it is likely that the string needs to be marked
-// as an LTR string (using base::i18n::WrapStringWithLTRFormatting()) so that it
-// is displayed properly in an RTL context. Please refer to
-// http://crbug.com/6487 for more information.
-GFX_EXPORT base::string16 ElideUrl(const GURL& url,
- const gfx::FontList& font_list,
- float available_pixel_width,
- const std::string& languages);
-
-enum ElideBehavior {
- // Add ellipsis at the end of the string.
- ELIDE_AT_END,
- // Add ellipsis in the middle of the string.
- ELIDE_IN_MIDDLE,
- // Truncate the end of the string.
- TRUNCATE_AT_END
+// Helper class to split + elide text, while respecting UTF16 surrogate pairs.
+class StringSlicer {
+ public:
+ StringSlicer(const base::string16& text,
+ const base::string16& ellipsis,
+ bool elide_in_middle,
+ bool elide_at_beginning);
+
+ // Cuts |text_| to be |length| characters long. If |elide_in_middle_| is true,
+ // the middle of the string is removed to leave equal-length pieces from the
+ // beginning and end of the string; otherwise, the end of the string is
+ // removed and only the beginning remains. If |insert_ellipsis| is true,
+ // then an ellipsis character will be inserted at the cut point.
+ base::string16 CutString(size_t length, bool insert_ellipsis);
+
+ private:
+ // Returns a valid cut boundary at or before/after |index|.
+ size_t FindValidBoundaryBefore(size_t index) const;
+ size_t FindValidBoundaryAfter(size_t index) const;
+
+ // The text to be sliced.
+ const base::string16& text_;
+
+ // Ellipsis string to use.
+ const base::string16& ellipsis_;
+
+ // If true, the middle of the string will be elided.
+ bool elide_in_middle_;
+
+ // If true, the beginning of the string will be elided.
+ bool elide_at_beginning_;
+
+ DISALLOW_COPY_AND_ASSIGN(StringSlicer);
};
-// Elides |text| to fit in |available_pixel_width| according to the specified
-// |elide_behavior|.
+// Elides |text| to fit the |available_pixel_width| with the specified behavior.
GFX_EXPORT base::string16 ElideText(const base::string16& text,
const gfx::FontList& font_list,
float available_pixel_width,
ElideBehavior elide_behavior);
-// Obsolete version. Use the above version which takes gfx::FontList.
-GFX_EXPORT base::string16 ElideText(const base::string16& text,
- const gfx::Font& font,
- float available_pixel_width,
- ElideBehavior elide_behavior);
// Elide a filename to fit a given pixel width, with an emphasis on not hiding
// the extension unless we have to. If filename contains a path, the path will
@@ -93,45 +79,9 @@ GFX_EXPORT base::string16 ElideFilename(const base::FilePath& filename,
const gfx::FontList& font_list,
float available_pixel_width);
-// SortedDisplayURL maintains a string from a URL suitable for display to the
-// use. SortedDisplayURL also provides a function used for comparing two
-// SortedDisplayURLs for use in visually ordering the SortedDisplayURLs.
-//
-// SortedDisplayURL is relatively cheap and supports value semantics.
-class GFX_EXPORT SortedDisplayURL {
- public:
- SortedDisplayURL(const GURL& url, const std::string& languages);
- SortedDisplayURL();
- ~SortedDisplayURL();
-
- // Compares this SortedDisplayURL to |url| using |collator|. Returns a value
- // < 0, = 1 or > 0 as to whether this url is less then, equal to or greater
- // than the supplied url.
- int Compare(const SortedDisplayURL& other, icu::Collator* collator) const;
-
- // Returns the display string for the URL.
- const base::string16& display_url() const { return display_url_; }
-
- private:
- // Returns everything after the host. This is used by Compare if the hosts
- // match.
- base::string16 AfterHost() const;
-
- // Host name minus 'www.'. Used by Compare.
- base::string16 sort_host_;
-
- // End of the prefix (spec and separator) in display_url_.
- size_t prefix_end_;
-
- base::string16 display_url_;
-
- DISALLOW_COPY_AND_ASSIGN(SortedDisplayURL);
-};
-
-// Functions to elide strings when the font information is unknown. As
-// opposed to the above functions, the ElideString() and
-// ElideRectangleString() functions operate in terms of character units,
-// not pixels.
+// Functions to elide strings when the font information is unknown. As opposed
+// to the above functions, ElideString() and ElideRectangleString() operate in
+// terms of character units, not pixels.
// If the size of |input| is more than |max_len|, this function returns
// true and |input| is shortened into |output| by removing chars in the
diff --git a/chromium/ui/gfx/text_elider_unittest.cc b/chromium/ui/gfx/text_elider_unittest.cc
index 5fa74cbd101..0b6bcad7f5a 100644
--- a/chromium/ui/gfx/text_elider_unittest.cc
+++ b/chromium/ui/gfx/text_elider_unittest.cc
@@ -15,7 +15,12 @@
#include "ui/gfx/font.h"
#include "ui/gfx/font_list.h"
#include "ui/gfx/text_utils.h"
-#include "url/gurl.h"
+
+using base::ASCIIToUTF16;
+using base::UTF16ToUTF8;
+using base::UTF16ToWide;
+using base::UTF8ToUTF16;
+using base::WideToUTF16;
namespace gfx {
@@ -32,8 +37,8 @@ struct FileTestcase {
};
struct UTF16Testcase {
- const string16 input;
- const string16 output;
+ const base::string16 input;
+ const base::string16 output;
};
struct TestData {
@@ -42,24 +47,12 @@ struct TestData {
const int compare_result;
};
-void RunUrlTest(Testcase* testcases, size_t num_testcases) {
- static const FontList font_list;
- for (size_t i = 0; i < num_testcases; ++i) {
- const GURL url(testcases[i].input);
- // Should we test with non-empty language list?
- // That's kinda redundant with net_util_unittests.
- const float available_width =
- GetStringWidthF(UTF8ToUTF16(testcases[i].output), font_list);
- EXPECT_EQ(UTF8ToUTF16(testcases[i].output),
- ElideUrl(url, font_list, available_width, std::string()));
- }
-}
-
} // namespace
// TODO(ios): This test fails on iOS because iOS version of GetStringWidthF
// that calls [NSString sizeWithFont] returns the rounded string width.
-#if defined(OS_IOS)
+// TODO(338784): Enable this on android.
+#if defined(OS_IOS) || defined(OS_ANDROID)
#define MAYBE_ElideEmail DISABLED_ElideEmail
#else
#define MAYBE_ElideEmail ElideEmail
@@ -111,16 +104,21 @@ TEST(TextEliderTest, MAYBE_ElideEmail) {
const FontList font_list;
for (size_t i = 0; i < arraysize(testcases); ++i) {
- const string16 expected_output = UTF8ToUTF16(testcases[i].output);
+ const base::string16 expected_output = UTF8ToUTF16(testcases[i].output);
EXPECT_EQ(expected_output,
- ElideEmail(
- UTF8ToUTF16(testcases[i].input),
- font_list,
- GetStringWidthF(expected_output, font_list)));
+ ElideText(UTF8ToUTF16(testcases[i].input), font_list,
+ GetStringWidthF(expected_output, font_list),
+ ELIDE_EMAIL));
}
}
-TEST(TextEliderTest, ElideEmailMoreSpace) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideEmailMoreSpace DISABLED_ElideEmailMoreSpace
+#else
+#define MAYBE_ElideEmailMoreSpace ElideEmailMoreSpace
+#endif
+TEST(TextEliderTest, MAYBE_ElideEmailMoreSpace) {
const int test_width_factors[] = {
100,
10000,
@@ -139,141 +137,17 @@ TEST(TextEliderTest, ElideEmailMoreSpace) {
font_list.GetExpectedTextWidth(test_width_factors[i]);
for (size_t j = 0; j < arraysize(test_emails); ++j) {
// Extra space is available: the email should not be elided.
- const string16 test_email = UTF8ToUTF16(test_emails[j]);
- EXPECT_EQ(test_email, ElideEmail(test_email, font_list, test_width));
+ const base::string16 test_email = UTF8ToUTF16(test_emails[j]);
+ EXPECT_EQ(test_email,
+ ElideText(test_email, font_list, test_width, ELIDE_EMAIL));
}
}
}
-// Test eliding of commonplace URLs.
-TEST(TextEliderTest, TestGeneralEliding) {
- const std::string kEllipsisStr(kEllipsis);
- Testcase testcases[] = {
- {"http://www.google.com/intl/en/ads/",
- "www.google.com/intl/en/ads/"},
- {"http://www.google.com/intl/en/ads/", "www.google.com/intl/en/ads/"},
- {"http://www.google.com/intl/en/ads/",
- "google.com/intl/" + kEllipsisStr + "/ads/"},
- {"http://www.google.com/intl/en/ads/",
- "google.com/" + kEllipsisStr + "/ads/"},
- {"http://www.google.com/intl/en/ads/", "google.com/" + kEllipsisStr},
- {"http://www.google.com/intl/en/ads/", "goog" + kEllipsisStr},
- {"https://subdomain.foo.com/bar/filename.html",
- "subdomain.foo.com/bar/filename.html"},
- {"https://subdomain.foo.com/bar/filename.html",
- "subdomain.foo.com/" + kEllipsisStr + "/filename.html"},
- {"http://subdomain.foo.com/bar/filename.html",
- kEllipsisStr + "foo.com/" + kEllipsisStr + "/filename.html"},
- {"http://www.google.com/intl/en/ads/?aLongQueryWhichIsNotRequired",
- "www.google.com/intl/en/ads/?aLongQ" + kEllipsisStr},
- };
-
- RunUrlTest(testcases, arraysize(testcases));
-}
-
-// When there is very little space available, the elision code will shorten
-// both path AND file name to an ellipsis - ".../...". To avoid this result,
-// there is a hack in place that simply treats them as one string in this
-// case.
-TEST(TextEliderTest, TestTrailingEllipsisSlashEllipsisHack) {
- const std::string kEllipsisStr(kEllipsis);
-
- // Very little space, would cause double ellipsis.
- FontList font_list;
- GURL url("http://battersbox.com/directory/foo/peter_paul_and_mary.html");
- float available_width = GetStringWidthF(
- UTF8ToUTF16("battersbox.com/" + kEllipsisStr + "/" + kEllipsisStr),
- font_list);
-
- // Create the expected string, after elision. Depending on font size, the
- // directory might become /dir... or /di... or/d... - it never should be
- // shorter than that. (If it is, the font considers d... to be longer
- // than .../... - that should never happen).
- ASSERT_GT(GetStringWidthF(UTF8ToUTF16(kEllipsisStr + "/" + kEllipsisStr),
- font_list),
- GetStringWidthF(UTF8ToUTF16("d" + kEllipsisStr), font_list));
- GURL long_url("http://battersbox.com/directorynameisreallylongtoforcetrunc");
- string16 expected =
- ElideUrl(long_url, font_list, available_width, std::string());
- // Ensure that the expected result still contains part of the directory name.
- ASSERT_GT(expected.length(), std::string("battersbox.com/d").length());
- EXPECT_EQ(expected,
- ElideUrl(url, font_list, available_width, std::string()));
-
- // More space available - elide directories, partially elide filename.
- Testcase testcases[] = {
- {"http://battersbox.com/directory/foo/peter_paul_and_mary.html",
- "battersbox.com/" + kEllipsisStr + "/peter" + kEllipsisStr},
- };
- RunUrlTest(testcases, arraysize(testcases));
-}
-
-// Test eliding of empty strings, URLs with ports, passwords, queries, etc.
-TEST(TextEliderTest, TestMoreEliding) {
- const std::string kEllipsisStr(kEllipsis);
- Testcase testcases[] = {
- {"http://www.google.com/foo?bar", "www.google.com/foo?bar"},
- {"http://xyz.google.com/foo?bar", "xyz.google.com/foo?" + kEllipsisStr},
- {"http://xyz.google.com/foo?bar", "xyz.google.com/foo" + kEllipsisStr},
- {"http://xyz.google.com/foo?bar", "xyz.google.com/fo" + kEllipsisStr},
- {"http://a.b.com/pathname/c?d", "a.b.com/" + kEllipsisStr + "/c?d"},
- {"", ""},
- {"http://foo.bar..example.com...hello/test/filename.html",
- "foo.bar..example.com...hello/" + kEllipsisStr + "/filename.html"},
- {"http://foo.bar../", "foo.bar.."},
- {"http://xn--1lq90i.cn/foo", "\xe5\x8c\x97\xe4\xba\xac.cn/foo"},
- {"http://me:mypass@secrethost.com:99/foo?bar#baz",
- "secrethost.com:99/foo?bar#baz"},
- {"http://me:mypass@ss%xxfdsf.com/foo", "ss%25xxfdsf.com/foo"},
- {"mailto:elgoato@elgoato.com", "mailto:elgoato@elgoato.com"},
- {"javascript:click(0)", "javascript:click(0)"},
- {"https://chess.eecs.berkeley.edu:4430/login/arbitfilename",
- "chess.eecs.berkeley.edu:4430/login/arbitfilename"},
- {"https://chess.eecs.berkeley.edu:4430/login/arbitfilename",
- kEllipsisStr + "berkeley.edu:4430/" + kEllipsisStr + "/arbitfilename"},
-
- // Unescaping.
- {"http://www/%E4%BD%A0%E5%A5%BD?q=%E4%BD%A0%E5%A5%BD#\xe4\xbd\xa0",
- "www/\xe4\xbd\xa0\xe5\xa5\xbd?q=\xe4\xbd\xa0\xe5\xa5\xbd#\xe4\xbd\xa0"},
-
- // Invalid unescaping for path. The ref will always be valid UTF-8. We don't
- // bother to do too many edge cases, since these are handled by the escaper
- // unittest.
- {"http://www/%E4%A0%E5%A5%BD?q=%E4%BD%A0%E5%A5%BD#\xe4\xbd\xa0",
- "www/%E4%A0%E5%A5%BD?q=\xe4\xbd\xa0\xe5\xa5\xbd#\xe4\xbd\xa0"},
- };
-
- RunUrlTest(testcases, arraysize(testcases));
-}
-
-// Test eliding of file: URLs.
-TEST(TextEliderTest, TestFileURLEliding) {
- const std::string kEllipsisStr(kEllipsis);
- Testcase testcases[] = {
- {"file:///C:/path1/path2/path3/filename",
- "file:///C:/path1/path2/path3/filename"},
- {"file:///C:/path1/path2/path3/filename",
- "C:/path1/path2/path3/filename"},
-// GURL parses "file:///C:path" differently on windows than it does on posix.
-#if defined(OS_WIN)
- {"file:///C:path1/path2/path3/filename",
- "C:/path1/path2/" + kEllipsisStr + "/filename"},
- {"file:///C:path1/path2/path3/filename",
- "C:/path1/" + kEllipsisStr + "/filename"},
- {"file:///C:path1/path2/path3/filename",
- "C:/" + kEllipsisStr + "/filename"},
-#endif
- {"file://filer/foo/bar/file", "filer/foo/bar/file"},
- {"file://filer/foo/bar/file", "filer/foo/" + kEllipsisStr + "/file"},
- {"file://filer/foo/bar/file", "filer/" + kEllipsisStr + "/file"},
- };
-
- RunUrlTest(testcases, arraysize(testcases));
-}
-
// TODO(ios): This test fails on iOS because iOS version of GetStringWidthF
// that calls [NSString sizeWithFont] returns the rounded string width.
-#if defined(OS_IOS)
+// TODO(338784): Enable this on android.
+#if defined(OS_IOS) || defined(OS_ANDROID)
#define MAYBE_TestFilenameEliding DISABLED_TestFilenameEliding
#else
#define MAYBE_TestFilenameEliding TestFilenameEliding
@@ -320,14 +194,20 @@ TEST(TextEliderTest, MAYBE_TestFilenameEliding) {
static const FontList font_list;
for (size_t i = 0; i < arraysize(testcases); ++i) {
base::FilePath filepath(testcases[i].input);
- string16 expected = UTF8ToUTF16(testcases[i].output);
+ base::string16 expected = UTF8ToUTF16(testcases[i].output);
expected = base::i18n::GetDisplayStringInLTRDirectionality(expected);
EXPECT_EQ(expected, ElideFilename(filepath, font_list,
GetStringWidthF(UTF8ToUTF16(testcases[i].output), font_list)));
}
}
-TEST(TextEliderTest, ElideTextTruncate) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideTextTruncate DISABLED_ElideTextTruncate
+#else
+#define MAYBE_ElideTextTruncate ElideTextTruncate
+#endif
+TEST(TextEliderTest, MAYBE_ElideTextTruncate) {
const FontList font_list;
const float kTestWidth = GetStringWidthF(ASCIIToUTF16("Test"), font_list);
struct TestData {
@@ -344,13 +224,19 @@ TEST(TextEliderTest, ElideTextTruncate) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list,
- cases[i].width, TRUNCATE_AT_END);
+ base::string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list,
+ cases[i].width, TRUNCATE);
EXPECT_EQ(cases[i].output, UTF16ToUTF8(result));
}
}
-TEST(TextEliderTest, ElideTextEllipsis) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideTextEllipsis DISABLED_ElideTextEllipsis
+#else
+#define MAYBE_ElideTextEllipsis ElideTextEllipsis
+#endif
+TEST(TextEliderTest, MAYBE_ElideTextEllipsis) {
const FontList font_list;
const float kTestWidth = GetStringWidthF(ASCIIToUTF16("Test"), font_list);
const char* kEllipsis = "\xE2\x80\xA6";
@@ -370,79 +256,132 @@ TEST(TextEliderTest, ElideTextEllipsis) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list,
- cases[i].width, ELIDE_AT_END);
+ base::string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list,
+ cases[i].width, ELIDE_TAIL);
EXPECT_EQ(cases[i].output, UTF16ToUTF8(result));
}
}
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideTextEllipsisFront DISABLED_ElideTextEllipsisFront
+#else
+#define MAYBE_ElideTextEllipsisFront ElideTextEllipsisFront
+#endif
+TEST(TextEliderTest, MAYBE_ElideTextEllipsisFront) {
+ const FontList font_list;
+ const float kTestWidth = GetStringWidthF(ASCIIToUTF16("Test"), font_list);
+ const std::string kEllipsisStr(kEllipsis);
+ const float kEllipsisWidth =
+ GetStringWidthF(UTF8ToUTF16(kEllipsis), font_list);
+ const float kEllipsis23Width =
+ GetStringWidthF(UTF8ToUTF16(kEllipsisStr + "23"), font_list);
+ struct TestData {
+ const char* input;
+ float width;
+ const base::string16 output;
+ } cases[] = {
+ { "", 0, base::string16() },
+ { "Test", 0, base::string16() },
+ { "Test", kEllipsisWidth, UTF8ToUTF16(kEllipsisStr) },
+ { "", kTestWidth, base::string16() },
+ { "Tes", kTestWidth, ASCIIToUTF16("Tes") },
+ { "Test", kTestWidth, ASCIIToUTF16("Test") },
+ { "Test123", kEllipsis23Width, UTF8ToUTF16(kEllipsisStr + "23") },
+ };
+
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
+ base::string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list,
+ cases[i].width, ELIDE_HEAD);
+ EXPECT_EQ(cases[i].output, result);
+ }
+}
+
// Checks that all occurrences of |first_char| are followed by |second_char| and
// all occurrences of |second_char| are preceded by |first_char| in |text|.
-static void CheckSurrogatePairs(const string16& text,
- char16 first_char,
- char16 second_char) {
+static void CheckSurrogatePairs(const base::string16& text,
+ base::char16 first_char,
+ base::char16 second_char) {
size_t index = text.find_first_of(first_char);
- while (index != string16::npos) {
+ while (index != base::string16::npos) {
EXPECT_LT(index, text.length() - 1);
EXPECT_EQ(second_char, text[index + 1]);
index = text.find_first_of(first_char, index + 1);
}
index = text.find_first_of(second_char);
- while (index != string16::npos) {
+ while (index != base::string16::npos) {
EXPECT_GT(index, 0U);
EXPECT_EQ(first_char, text[index - 1]);
index = text.find_first_of(second_char, index + 1);
}
}
-TEST(TextEliderTest, ElideTextSurrogatePairs) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideTextSurrogatePairs DISABLED_ElideTextSurrogatePairs
+#else
+#define MAYBE_ElideTextSurrogatePairs ElideTextSurrogatePairs
+#endif
+TEST(TextEliderTest, MAYBE_ElideTextSurrogatePairs) {
const FontList font_list;
// The below is 'MUSICAL SYMBOL G CLEF', which is represented in UTF-16 as
// two characters forming a surrogate pair 0x0001D11E.
const std::string kSurrogate = "\xF0\x9D\x84\x9E";
- const string16 kTestString =
+ const base::string16 kTestString =
UTF8ToUTF16(kSurrogate + "ab" + kSurrogate + kSurrogate + "cd");
const float kTestStringWidth = GetStringWidthF(kTestString, font_list);
- const char16 kSurrogateFirstChar = kTestString[0];
- const char16 kSurrogateSecondChar = kTestString[1];
- string16 result;
+ const base::char16 kSurrogateFirstChar = kTestString[0];
+ const base::char16 kSurrogateSecondChar = kTestString[1];
+ base::string16 result;
// Elide |kTextString| to all possible widths and check that no instance of
// |kSurrogate| was split in two.
for (float width = 0; width <= kTestStringWidth; width++) {
- result = ElideText(kTestString, font_list, width, TRUNCATE_AT_END);
+ result = ElideText(kTestString, font_list, width, TRUNCATE);
+ CheckSurrogatePairs(result, kSurrogateFirstChar, kSurrogateSecondChar);
+
+ result = ElideText(kTestString, font_list, width, ELIDE_TAIL);
CheckSurrogatePairs(result, kSurrogateFirstChar, kSurrogateSecondChar);
- result = ElideText(kTestString, font_list, width, ELIDE_AT_END);
+ result = ElideText(kTestString, font_list, width, ELIDE_MIDDLE);
CheckSurrogatePairs(result, kSurrogateFirstChar, kSurrogateSecondChar);
- result = ElideText(kTestString, font_list, width, ELIDE_IN_MIDDLE);
+ result = ElideText(kTestString, font_list, width, ELIDE_HEAD);
CheckSurrogatePairs(result, kSurrogateFirstChar, kSurrogateSecondChar);
}
}
-TEST(TextEliderTest, ElideTextLongStrings) {
- const string16 kEllipsisStr = UTF8ToUTF16(kEllipsis);
- string16 data_scheme(UTF8ToUTF16("data:text/plain,"));
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideTextLongStrings DISABLED_ElideTextLongStrings
+#else
+#define MAYBE_ElideTextLongStrings ElideTextLongStrings
+#endif
+TEST(TextEliderTest, MAYBE_ElideTextLongStrings) {
+ const base::string16 kEllipsisStr = UTF8ToUTF16(kEllipsis);
+ base::string16 data_scheme(UTF8ToUTF16("data:text/plain,"));
size_t data_scheme_length = data_scheme.length();
- string16 ten_a(10, 'a');
- string16 hundred_a(100, 'a');
- string16 thousand_a(1000, 'a');
- string16 ten_thousand_a(10000, 'a');
- string16 hundred_thousand_a(100000, 'a');
- string16 million_a(1000000, 'a');
+ base::string16 ten_a(10, 'a');
+ base::string16 hundred_a(100, 'a');
+ base::string16 thousand_a(1000, 'a');
+ base::string16 ten_thousand_a(10000, 'a');
+ base::string16 hundred_thousand_a(100000, 'a');
+ base::string16 million_a(1000000, 'a');
+
+ // TODO(gbillock): Improve these tests by adding more string diversity and
+ // doing string compares instead of length compares. See bug 338836.
size_t number_of_as = 156;
- string16 long_string_end(
- data_scheme + string16(number_of_as, 'a') + kEllipsisStr);
+ base::string16 long_string_end(
+ data_scheme + base::string16(number_of_as, 'a') + kEllipsisStr);
UTF16Testcase testcases_end[] = {
- {data_scheme + ten_a, data_scheme + ten_a},
- {data_scheme + hundred_a, data_scheme + hundred_a},
- {data_scheme + thousand_a, long_string_end},
- {data_scheme + ten_thousand_a, long_string_end},
- {data_scheme + hundred_thousand_a, long_string_end},
- {data_scheme + million_a, long_string_end},
+ { data_scheme + ten_a, data_scheme + ten_a },
+ { data_scheme + hundred_a, data_scheme + hundred_a },
+ { data_scheme + thousand_a, long_string_end },
+ { data_scheme + ten_thousand_a, long_string_end },
+ { data_scheme + hundred_thousand_a, long_string_end },
+ { data_scheme + million_a, long_string_end },
};
const FontList font_list;
@@ -451,85 +390,58 @@ TEST(TextEliderTest, ElideTextLongStrings) {
// Compare sizes rather than actual contents because if the test fails,
// output is rather long.
EXPECT_EQ(testcases_end[i].output.size(),
- ElideText(
- testcases_end[i].input,
- font_list,
- GetStringWidthF(testcases_end[i].output, font_list),
- ELIDE_AT_END).size());
+ ElideText(testcases_end[i].input, font_list,
+ GetStringWidthF(testcases_end[i].output, font_list),
+ ELIDE_TAIL).size());
EXPECT_EQ(kEllipsisStr,
ElideText(testcases_end[i].input, font_list, ellipsis_width,
- ELIDE_AT_END));
+ ELIDE_TAIL));
}
size_t number_of_trailing_as = (data_scheme_length + number_of_as) / 2;
- string16 long_string_middle(data_scheme +
- string16(number_of_as - number_of_trailing_as, 'a') + kEllipsisStr +
- string16(number_of_trailing_as, 'a'));
+ base::string16 long_string_middle(data_scheme +
+ base::string16(number_of_as - number_of_trailing_as, 'a') + kEllipsisStr +
+ base::string16(number_of_trailing_as, 'a'));
UTF16Testcase testcases_middle[] = {
- {data_scheme + ten_a, data_scheme + ten_a},
- {data_scheme + hundred_a, data_scheme + hundred_a},
- {data_scheme + thousand_a, long_string_middle},
- {data_scheme + ten_thousand_a, long_string_middle},
- {data_scheme + hundred_thousand_a, long_string_middle},
- {data_scheme + million_a, long_string_middle},
+ { data_scheme + ten_a, data_scheme + ten_a },
+ { data_scheme + hundred_a, data_scheme + hundred_a },
+ { data_scheme + thousand_a, long_string_middle },
+ { data_scheme + ten_thousand_a, long_string_middle },
+ { data_scheme + hundred_thousand_a, long_string_middle },
+ { data_scheme + million_a, long_string_middle },
};
for (size_t i = 0; i < arraysize(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(),
- ElideText(
- testcases_middle[i].input,
- font_list,
- GetStringWidthF(testcases_middle[i].output, font_list),
- ELIDE_AT_END).size());
+ ElideText(testcases_middle[i].input, font_list,
+ GetStringWidthF(testcases_middle[i].output, font_list),
+ ELIDE_MIDDLE).size());
EXPECT_EQ(kEllipsisStr,
ElideText(testcases_middle[i].input, font_list, ellipsis_width,
- ELIDE_AT_END));
+ ELIDE_MIDDLE));
}
-}
-
-// Verifies display_url is set correctly.
-TEST(TextEliderTest, SortedDisplayURL) {
- SortedDisplayURL d_url(GURL("http://www.google.com"), std::string());
- EXPECT_EQ("www.google.com", UTF16ToASCII(d_url.display_url()));
-}
-
-// Verifies DisplayURL::Compare works correctly.
-TEST(TextEliderTest, SortedDisplayURLCompare) {
- UErrorCode create_status = U_ZERO_ERROR;
- scoped_ptr<icu::Collator> collator(
- icu::Collator::createInstance(create_status));
- if (!U_SUCCESS(create_status))
- return;
-
- TestData tests[] = {
- // IDN comparison. Hosts equal, so compares on path.
- { "http://xn--1lq90i.cn/a", "http://xn--1lq90i.cn/b", -1},
- // Because the host and after host match, this compares the full url.
- { "http://www.x/b", "http://x/b", -1 },
-
- // Because the host and after host match, this compares the full url.
- { "http://www.a:1/b", "http://a:1/b", 1 },
-
- // The hosts match, so these end up comparing on the after host portion.
- { "http://www.x:0/b", "http://x:1/b", -1 },
- { "http://www.x/a", "http://x/b", -1 },
- { "http://x/b", "http://www.x/a", 1 },
-
- // Trivial Equality.
- { "http://a/", "http://a/", 0 },
-
- // Compares just hosts.
- { "http://www.a/", "http://b/", -1 },
+ base::string16 long_string_beginning(
+ kEllipsisStr + base::string16(number_of_as, 'a'));
+ UTF16Testcase testcases_beginning[] = {
+ { data_scheme + ten_a, data_scheme + ten_a },
+ { data_scheme + hundred_a, data_scheme + hundred_a },
+ { data_scheme + thousand_a, long_string_beginning },
+ { data_scheme + ten_thousand_a, long_string_beginning },
+ { data_scheme + hundred_thousand_a, long_string_beginning },
+ { data_scheme + million_a, long_string_beginning },
};
-
- for (size_t i = 0; i < arraysize(tests); ++i) {
- SortedDisplayURL url1(GURL(tests[i].a), std::string());
- SortedDisplayURL url2(GURL(tests[i].b), std::string());
- EXPECT_EQ(tests[i].compare_result, url1.Compare(url2, collator.get()));
- EXPECT_EQ(-tests[i].compare_result, url2.Compare(url1, collator.get()));
+ for (size_t i = 0; i < arraysize(testcases_beginning); ++i) {
+ EXPECT_EQ(testcases_beginning[i].output.size(),
+ ElideText(
+ testcases_beginning[i].input, font_list,
+ GetStringWidthF(testcases_beginning[i].output, font_list),
+ ELIDE_HEAD).size());
+ EXPECT_EQ(kEllipsisStr,
+ ElideText(testcases_beginning[i].input, font_list, ellipsis_width,
+ ELIDE_HEAD));
}
}
@@ -553,7 +465,7 @@ TEST(TextEliderTest, ElideString) {
{ "Hello, my name is Tom", 100, false, "Hello, my name is Tom" }
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- string16 output;
+ base::string16 output;
EXPECT_EQ(cases[i].result,
ElideString(UTF8ToUTF16(cases[i].input),
cases[i].max_len, &output));
@@ -561,7 +473,13 @@ TEST(TextEliderTest, ElideString) {
}
}
-TEST(TextEliderTest, ElideRectangleText) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideRectangleText DISABLED_ElideRectangleText
+#else
+#define MAYBE_ElideRectangleText ElideRectangleText
+#endif
+TEST(TextEliderTest, MAYBE_ElideRectangleText) {
const FontList font_list;
const int line_height = font_list.GetHeight();
const float test_width = GetStringWidthF(ASCIIToUTF16("Test"), font_list);
@@ -601,7 +519,7 @@ TEST(TextEliderTest, ElideRectangleText) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- std::vector<string16> lines;
+ std::vector<base::string16> lines;
EXPECT_EQ(cases[i].truncated_y ? INSUFFICIENT_SPACE_VERTICAL : 0,
ElideRectangleText(UTF8ToUTF16(cases[i].input),
font_list,
@@ -618,7 +536,14 @@ TEST(TextEliderTest, ElideRectangleText) {
}
}
-TEST(TextEliderTest, ElideRectangleTextPunctuation) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideRectangleTextPunctuation \
+ DISABLED_ElideRectangleTextPunctuation
+#else
+#define MAYBE_ElideRectangleTextPunctuation ElideRectangleTextPunctuation
+#endif
+TEST(TextEliderTest, MAYBE_ElideRectangleTextPunctuation) {
const FontList font_list;
const int line_height = font_list.GetHeight();
const float test_width = GetStringWidthF(ASCIIToUTF16("Test"), font_list);
@@ -639,7 +564,7 @@ TEST(TextEliderTest, ElideRectangleTextPunctuation) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- std::vector<string16> lines;
+ std::vector<base::string16> lines;
const WordWrapBehavior wrap_behavior =
(cases[i].wrap_words ? WRAP_LONG_WORDS : TRUNCATE_LONG_WORDS);
EXPECT_EQ(cases[i].truncated_x ? INSUFFICIENT_SPACE_HORIZONTAL : 0,
@@ -658,10 +583,17 @@ TEST(TextEliderTest, ElideRectangleTextPunctuation) {
}
}
-TEST(TextEliderTest, ElideRectangleTextLongWords) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideRectangleTextLongWords DISABLED_ElideRectangleTextLongWords
+#else
+#define MAYBE_ElideRectangleTextLongWords ElideRectangleTextLongWords
+#endif
+TEST(TextEliderTest, MAYBE_ElideRectangleTextLongWords) {
const FontList font_list;
const int kAvailableHeight = 1000;
- const string16 kElidedTesting = UTF8ToUTF16(std::string("Tes") + kEllipsis);
+ const base::string16 kElidedTesting =
+ UTF8ToUTF16(std::string("Tes") + kEllipsis);
const float elided_width = GetStringWidthF(kElidedTesting, font_list);
const float test_width = GetStringWidthF(ASCIIToUTF16("Test"), font_list);
@@ -702,7 +634,7 @@ TEST(TextEliderTest, ElideRectangleTextLongWords) {
};
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
- std::vector<string16> lines;
+ std::vector<base::string16> lines;
EXPECT_EQ(cases[i].truncated_x ? INSUFFICIENT_SPACE_HORIZONTAL : 0,
ElideRectangleText(UTF8ToUTF16(cases[i].input),
font_list,
@@ -722,7 +654,14 @@ TEST(TextEliderTest, ElideRectangleTextLongWords) {
// fail because the truncated integer width is returned for the string
// and the accumulation of the truncated values causes the elide function
// to wrap incorrectly.
-TEST(TextEliderTest, ElideRectangleTextCheckLineWidth) {
+// TODO(338784): Enable this on android.
+#if defined(OS_ANDROID)
+#define MAYBE_ElideRectangleTextCheckLineWidth \
+ DISABLED_ElideRectangleTextCheckLineWidth
+#else
+#define MAYBE_ElideRectangleTextCheckLineWidth ElideRectangleTextCheckLineWidth
+#endif
+TEST(TextEliderTest, MAYBE_ElideRectangleTextCheckLineWidth) {
FontList font_list;
#if defined(OS_MACOSX) && !defined(OS_IOS)
// Use a specific font to expose the line width exceeding problem.
@@ -731,7 +670,7 @@ TEST(TextEliderTest, ElideRectangleTextCheckLineWidth) {
const float kAvailableWidth = 235;
const int kAvailableHeight = 1000;
const char text[] = "that Russian place we used to go to after fencing";
- std::vector<string16> lines;
+ std::vector<base::string16> lines;
EXPECT_EQ(0, ElideRectangleText(UTF8ToUTF16(text),
font_list,
kAvailableWidth,
@@ -816,7 +755,7 @@ TEST(TextEliderTest, ElideRectangleString) {
{ "Hi, my name is\nTom", 2, 20, false, "Hi, my name is\nTom" },
{ "Hi, my name is Tom", 1, 40, false, "Hi, my name is Tom" },
};
- string16 output;
+ base::string16 output;
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
EXPECT_EQ(cases[i].result,
ElideRectangleString(UTF8ToUTF16(cases[i].input),
@@ -898,7 +837,7 @@ TEST(TextEliderTest, ElideRectangleStringNotStrict) {
{ "Hi, my name_is\nDick", 2, 20, false, "Hi, my name_is\nDick" },
{ "Hi, my name_is Dick", 1, 40, false, "Hi, my name_is Dick" },
};
- string16 output;
+ base::string16 output;
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
EXPECT_EQ(cases[i].result,
ElideRectangleString(UTF8ToUTF16(cases[i].input),
@@ -910,17 +849,17 @@ TEST(TextEliderTest, ElideRectangleStringNotStrict) {
TEST(TextEliderTest, ElideRectangleWide16) {
// Two greek words separated by space.
- const string16 str(WideToUTF16(
+ const base::string16 str(WideToUTF16(
L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9"
L"\x03bf\x03c2\x0020\x0399\x03c3\x03c4\x03cc\x03c2"));
- const string16 out1(WideToUTF16(
+ const base::string16 out1(WideToUTF16(
L"\x03a0\x03b1\x03b3\x03ba\n"
L"\x03cc\x03c3\x03bc\x03b9\n"
L"..."));
- const string16 out2(WideToUTF16(
+ const base::string16 out2(WideToUTF16(
L"\x03a0\x03b1\x03b3\x03ba\x03cc\x03c3\x03bc\x03b9\x03bf\x03c2\x0020\n"
L"\x0399\x03c3\x03c4\x03cc\x03c2"));
- string16 output;
+ base::string16 output;
EXPECT_TRUE(ElideRectangleString(str, 2, 4, true, &output));
EXPECT_EQ(out1, output);
EXPECT_FALSE(ElideRectangleString(str, 2, 12, true, &output));
@@ -929,19 +868,19 @@ TEST(TextEliderTest, ElideRectangleWide16) {
TEST(TextEliderTest, ElideRectangleWide32) {
// Four U+1D49C MATHEMATICAL SCRIPT CAPITAL A followed by space "aaaaa".
- const string16 str(UTF8ToUTF16(
+ const base::string16 str(UTF8ToUTF16(
"\xF0\x9D\x92\x9C\xF0\x9D\x92\x9C\xF0\x9D\x92\x9C\xF0\x9D\x92\x9C"
" aaaaa"));
- const string16 out(UTF8ToUTF16(
+ const base::string16 out(UTF8ToUTF16(
"\xF0\x9D\x92\x9C\xF0\x9D\x92\x9C\xF0\x9D\x92\x9C\n"
"\xF0\x9D\x92\x9C \naaa\n..."));
- string16 output;
+ base::string16 output;
EXPECT_TRUE(ElideRectangleString(str, 3, 3, true, &output));
EXPECT_EQ(out, output);
}
TEST(TextEliderTest, TruncateString) {
- string16 string = ASCIIToUTF16("foooooey bxxxar baz");
+ base::string16 string = ASCIIToUTF16("foooooey bxxxar baz");
// Make sure it doesn't modify the string if length > string length.
EXPECT_EQ(string, TruncateString(string, 100));
diff --git a/chromium/ui/gfx/text_utils_unittest.cc b/chromium/ui/gfx/text_utils_unittest.cc
index 1090b388b04..0c0127fc123 100644
--- a/chromium/ui/gfx/text_utils_unittest.cc
+++ b/chromium/ui/gfx/text_utils_unittest.cc
@@ -6,11 +6,12 @@
#include "base/strings/utf_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/font_list.h"
namespace gfx {
namespace {
-const char16 kAcceleratorChar = '&';
+const base::char16 kAcceleratorChar = '&';
TEST(TextUtilsTest, RemoveAcceleratorChar) {
struct TestData {
@@ -48,15 +49,33 @@ TEST(TextUtilsTest, RemoveAcceleratorChar) {
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) {
int accelerated_char_pos;
int accelerated_char_span;
- base::string16 result = RemoveAcceleratorChar(UTF8ToUTF16(cases[i].input),
- kAcceleratorChar,
- &accelerated_char_pos,
- &accelerated_char_span);
- EXPECT_EQ(result, UTF8ToUTF16(cases[i].output));
+ base::string16 result = RemoveAcceleratorChar(
+ base::UTF8ToUTF16(cases[i].input),
+ kAcceleratorChar,
+ &accelerated_char_pos,
+ &accelerated_char_span);
+ EXPECT_EQ(result, base::UTF8ToUTF16(cases[i].output));
EXPECT_EQ(accelerated_char_pos, cases[i].accelerated_char_pos);
EXPECT_EQ(accelerated_char_span, cases[i].accelerated_char_span);
}
}
+// Disabled on Ozone since there are no fonts: crbug.com/320050
+#if defined(USE_OZONE)
+#define MAYBE_GetStringWidth DISABLED_GetStringWidth
+#else
+#define MAYBE_GetStringWidth GetStringWidth
+#endif
+TEST(TextUtilsTest, MAYBE_GetStringWidth) {
+ FontList font_list;
+ EXPECT_EQ(GetStringWidth(base::string16(), font_list), 0);
+ EXPECT_GT(GetStringWidth(base::ASCIIToUTF16("a"), font_list),
+ GetStringWidth(base::string16(), font_list));
+ EXPECT_GT(GetStringWidth(base::ASCIIToUTF16("ab"), font_list),
+ GetStringWidth(base::ASCIIToUTF16("a"), font_list));
+ EXPECT_GT(GetStringWidth(base::ASCIIToUTF16("abc"), font_list),
+ GetStringWidth(base::ASCIIToUTF16("ab"), font_list));
+}
+
} // namespace
} // namespace gfx
diff --git a/chromium/ui/gfx/transform.h b/chromium/ui/gfx/transform.h
index 5e3b8303340..5440aac71f5 100644
--- a/chromium/ui/gfx/transform.h
+++ b/chromium/ui/gfx/transform.h
@@ -89,6 +89,9 @@ class GFX_EXPORT Transform {
// to |this|.
void Scale(SkMScalar x, SkMScalar y);
void Scale3d(SkMScalar x, SkMScalar y, SkMScalar z);
+ gfx::Vector2dF Scale2d() const {
+ return gfx::Vector2dF(matrix_.get(0, 0), matrix_.get(1, 1));
+ }
// Applies the current transformation on a translation and assigns the result
// to |this|.
@@ -136,6 +139,11 @@ class GFX_EXPORT Transform {
// translation.
bool IsIdentityOrIntegerTranslation() const;
+ // Returns true if the matrix had only scaling components.
+ bool IsScale2d() const {
+ return !(matrix_.getType() & ~SkMatrix44::kScale_Mask);
+ }
+
// Returns true if the matrix is has only scaling and translation components.
bool IsScaleOrTranslation() const {
int mask = SkMatrix44::kScale_Mask | SkMatrix44::kTranslate_Mask;
diff --git a/chromium/ui/gfx/utf16_indexing_unittest.cc b/chromium/ui/gfx/utf16_indexing_unittest.cc
index da2f8f5b56c..f93d6693660 100644
--- a/chromium/ui/gfx/utf16_indexing_unittest.cc
+++ b/chromium/ui/gfx/utf16_indexing_unittest.cc
@@ -9,8 +9,9 @@ namespace gfx {
TEST(UTF16IndexingTest, IndexOffsetConversions) {
// Valid surrogate pair surrounded by unpaired surrogates
- const char16 foo[] = {0xDC00, 0xD800, 0xD800, 0xDFFF, 0xDFFF, 0xDBFF, 0};
- const string16 s(foo);
+ const base::char16 foo[] =
+ {0xDC00, 0xD800, 0xD800, 0xDFFF, 0xDFFF, 0xDBFF, 0};
+ const base::string16 s(foo);
const size_t the_invalid_index = 3;
for (size_t i = 0; i <= s.length(); ++i)
EXPECT_EQ(i != the_invalid_index, IsValidCodePointIndex(s, i));
diff --git a/chromium/ui/gfx/vector2d.h b/chromium/ui/gfx/vector2d.h
index 8dd76324d1a..c0eefd23943 100644
--- a/chromium/ui/gfx/vector2d.h
+++ b/chromium/ui/gfx/vector2d.h
@@ -1,91 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
-// Defines a simple integer vector class. This class is used to indicate a
-// distance in two dimensions between two points. Subtracting two points should
-// produce a vector, and adding a vector to a point produces the point at the
-// vector's distance from the original point.
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/vector2d.h"
-#ifndef UI_GFX_VECTOR2D_H_
-#define UI_GFX_VECTOR2D_H_
-
-#include <string>
-
-#include "base/basictypes.h"
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/vector2d_f.h"
-
-namespace gfx {
-
-class GFX_EXPORT Vector2d {
- public:
- Vector2d() : x_(0), y_(0) {}
- Vector2d(int x, int y) : x_(x), y_(y) {}
-
- int x() const { return x_; }
- void set_x(int x) { x_ = x; }
-
- int y() const { return y_; }
- void set_y(int y) { y_ = y; }
-
- // True if both components of the vector are 0.
- bool IsZero() const;
-
- // Add the components of the |other| vector to the current vector.
- void Add(const Vector2d& other);
- // Subtract the components of the |other| vector from the current vector.
- void Subtract(const Vector2d& other);
-
- 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_;
- }
-
- void SetToMax(const Vector2d& other) {
- x_ = x_ >= other.x_ ? x_ : other.x_;
- y_ = y_ >= other.y_ ? 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;
- // Gives the diagonal length of the vector.
- float Length() const;
-
- std::string ToString() const;
-
- operator Vector2dF() const { return Vector2dF(x_, y_); }
-
- private:
- int x_;
- 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());
-}
-
-inline Vector2d operator+(const Vector2d& lhs, const Vector2d& rhs) {
- Vector2d result = lhs;
- result.Add(rhs);
- return result;
-}
-
-inline Vector2d operator-(const Vector2d& lhs, const Vector2d& rhs) {
- Vector2d result = lhs;
- result.Add(-rhs);
- return result;
-}
-
-} // namespace gfx
-
-#endif // UI_GFX_VECTOR2D_H_
diff --git a/chromium/ui/gfx/vector2d_conversions.h b/chromium/ui/gfx/vector2d_conversions.h
index 509a4567d10..5417e1c3f21 100644
--- a/chromium/ui/gfx/vector2d_conversions.h
+++ b/chromium/ui/gfx/vector2d_conversions.h
@@ -1,24 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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_VECTOR2D_CONVERSIONS_H_
-#define UI_GFX_VECTOR2D_CONVERSIONS_H_
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/vector2d_conversions.h"
-#include "ui/gfx/vector2d.h"
-#include "ui/gfx/vector2d_f.h"
-
-namespace gfx {
-
-// Returns a Vector2d with each component from the input Vector2dF floored.
-GFX_EXPORT Vector2d ToFlooredVector2d(const Vector2dF& vector2d);
-
-// Returns a Vector2d with each component from the input Vector2dF ceiled.
-GFX_EXPORT Vector2d ToCeiledVector2d(const Vector2dF& vector2d);
-
-// Returns a Vector2d with each component from the input Vector2dF rounded.
-GFX_EXPORT Vector2d ToRoundedVector2d(const Vector2dF& vector2d);
-
-} // namespace gfx
-
-#endif // UI_GFX_VECTOR2D_CONVERSIONS_H_
diff --git a/chromium/ui/gfx/vector2d_f.h b/chromium/ui/gfx/vector2d_f.h
index 289b9b7a8d1..28a51d3da85 100644
--- a/chromium/ui/gfx/vector2d_f.h
+++ b/chromium/ui/gfx/vector2d_f.h
@@ -1,112 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
-// Defines a simple float vector class. This class is used to indicate a
-// distance in two dimensions between two points. Subtracting two points should
-// produce a vector, and adding a vector to a point produces the point at the
-// vector's distance from the original point.
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/vector2d_f.h"
-#ifndef UI_GFX_VECTOR2D_F_H_
-#define UI_GFX_VECTOR2D_F_H_
-
-#include <string>
-
-#include "ui/gfx/gfx_export.h"
-
-namespace gfx {
-
-class GFX_EXPORT Vector2dF {
- public:
- Vector2dF() : x_(0), y_(0) {}
- Vector2dF(float x, float y) : x_(x), y_(y) {}
-
- float x() const { return x_; }
- void set_x(float x) { x_ = x; }
-
- float y() const { return y_; }
- void set_y(float y) { y_ = y; }
-
- // True if both components of the vector are 0.
- bool IsZero() const;
-
- // Add the components of the |other| vector to the current vector.
- void Add(const Vector2dF& other);
- // Subtract the components of the |other| vector from the current vector.
- void Subtract(const Vector2dF& other);
-
- void operator+=(const Vector2dF& other) { Add(other); }
- void operator-=(const Vector2dF& other) { Subtract(other); }
-
- void SetToMin(const Vector2dF& other) {
- x_ = x_ <= other.x_ ? x_ : other.x_;
- y_ = y_ <= other.y_ ? y_ : other.y_;
- }
-
- void SetToMax(const Vector2dF& other) {
- x_ = x_ >= other.x_ ? x_ : other.x_;
- y_ = y_ >= other.y_ ? y_ : other.y_;
- }
-
- // Gives the square of the diagonal length of the vector.
- double LengthSquared() const;
- // Gives the diagonal length of the vector.
- float Length() 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);
-
- std::string ToString() const;
-
- private:
- float x_;
- float y_;
-};
-
-inline 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) {
- return !(lhs == rhs);
-}
-
-inline Vector2dF operator-(const Vector2dF& v) {
- return Vector2dF(-v.x(), -v.y());
-}
-
-inline Vector2dF operator+(const Vector2dF& lhs, const Vector2dF& rhs) {
- Vector2dF result = lhs;
- result.Add(rhs);
- return result;
-}
-
-inline Vector2dF operator-(const Vector2dF& lhs, const Vector2dF& rhs) {
- Vector2dF result = lhs;
- result.Add(-rhs);
- return result;
-}
-
-// Return the cross product of two vectors.
-GFX_EXPORT double CrossProduct(const Vector2dF& lhs, const Vector2dF& rhs);
-
-// Return the dot product of two vectors.
-GFX_EXPORT double DotProduct(const Vector2dF& lhs, const Vector2dF& rhs);
-
-// Return a vector that is |v| scaled by the given scale factors along each
-// axis.
-GFX_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);
-}
-
-} // namespace gfx
-
-#endif // UI_GFX_VECTOR2D_F_H_
diff --git a/chromium/ui/gfx/vector3d_f.h b/chromium/ui/gfx/vector3d_f.h
index 0e91a362eca..ad0445fc258 100644
--- a/chromium/ui/gfx/vector3d_f.h
+++ b/chromium/ui/gfx/vector3d_f.h
@@ -1,124 +1,7 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// 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.
-// Defines a simple float vector class. This class is used to indicate a
-// distance in two dimensions between two points. Subtracting two points should
-// produce a vector, and adding a vector to a point produces the point at the
-// vector's distance from the original point.
+// TODO(beng): remove once callsites are patched.
+#include "ui/gfx/geometry/vector3d_f.h"
-#ifndef UI_GFX_VECTOR3D_F_H_
-#define UI_GFX_VECTOR3D_F_H_
-
-#include <string>
-
-#include "ui/gfx/gfx_export.h"
-#include "ui/gfx/vector2d_f.h"
-
-namespace gfx {
-
-class GFX_EXPORT Vector3dF {
- public:
- Vector3dF();
- Vector3dF(float x, float y, float z);
-
- explicit Vector3dF(const Vector2dF& other);
-
- float x() const { return x_; }
- void set_x(float x) { x_ = x; }
-
- float y() const { return y_; }
- void set_y(float y) { y_ = y; }
-
- float z() const { return z_; }
- void set_z(float z) { z_ = z; }
-
- // True if all components of the vector are 0.
- bool IsZero() const;
-
- // Add the components of the |other| vector to the current vector.
- void Add(const Vector3dF& other);
- // Subtract the components of the |other| vector from the current vector.
- void Subtract(const Vector3dF& other);
-
- void operator+=(const Vector3dF& other) { Add(other); }
- void operator-=(const Vector3dF& other) { Subtract(other); }
-
- void SetToMin(const Vector3dF& other) {
- x_ = x_ <= other.x_ ? x_ : other.x_;
- y_ = y_ <= other.y_ ? y_ : other.y_;
- z_ = z_ <= other.z_ ? z_ : other.z_;
- }
-
- void SetToMax(const Vector3dF& other) {
- x_ = x_ >= other.x_ ? x_ : other.x_;
- y_ = y_ >= other.y_ ? y_ : other.y_;
- z_ = z_ >= other.z_ ? z_ : other.z_;
- }
-
- // Gives the square of the diagonal length of the vector.
- double LengthSquared() const;
- // Gives the diagonal length of the vector.
- float Length() const;
-
- // Scale all components of the vector by |scale|.
- void Scale(float scale) { Scale(scale, scale, scale); }
- // Scale the each component of the vector by the given scale factors.
- void Scale(float x_scale, float y_scale, float z_scale);
-
- // Take the cross product of this vector with |other| and become the result.
- void Cross(const Vector3dF& other);
-
- std::string ToString() const;
-
- private:
- float x_;
- float y_;
- float z_;
-};
-
-inline bool operator==(const Vector3dF& lhs, const Vector3dF& rhs) {
- return lhs.x() == rhs.x() && lhs.y() == rhs.y() && lhs.z() == rhs.z();
-}
-
-inline Vector3dF operator-(const Vector3dF& v) {
- return Vector3dF(-v.x(), -v.y(), -v.z());
-}
-
-inline Vector3dF operator+(const Vector3dF& lhs, const Vector3dF& rhs) {
- Vector3dF result = lhs;
- result.Add(rhs);
- return result;
-}
-
-inline Vector3dF operator-(const Vector3dF& lhs, const Vector3dF& rhs) {
- Vector3dF result = lhs;
- result.Add(-rhs);
- return result;
-}
-
-// Return the cross product of two vectors.
-inline Vector3dF CrossProduct(const Vector3dF& lhs, const Vector3dF& rhs) {
- Vector3dF result = lhs;
- result.Cross(rhs);
- return result;
-}
-
-// Return the dot product of two vectors.
-GFX_EXPORT float DotProduct(const Vector3dF& lhs, const Vector3dF& rhs);
-
-// Return a vector that is |v| scaled by the given scale factors along each
-// axis.
-GFX_EXPORT Vector3dF ScaleVector3d(const Vector3dF& v,
- float x_scale,
- float y_scale,
- float z_scale);
-
-// Return a vector that is |v| scaled by the given scale factor.
-inline Vector3dF ScaleVector3d(const Vector3dF& v, float scale) {
- return ScaleVector3d(v, scale, scale, scale);
-}
-
-} // namespace gfx
-
-#endif // UI_GFX_VECTOR3D_F_H_
diff --git a/chromium/ui/gfx/win/dpi.cc b/chromium/ui/gfx/win/dpi.cc
index 6bc25dee646..e562a086c9a 100644
--- a/chromium/ui/gfx/win/dpi.cc
+++ b/chromium/ui/gfx/win/dpi.cc
@@ -20,6 +20,8 @@ namespace {
int kDefaultDPIX = 96;
int kDefaultDPIY = 96;
+bool force_highdpi_for_testing = false;
+
BOOL IsProcessDPIAwareWrapper() {
typedef BOOL(WINAPI *IsProcessDPIAwarePtr)(VOID);
IsProcessDPIAwarePtr is_process_dpi_aware_func =
@@ -33,33 +35,81 @@ BOOL IsProcessDPIAwareWrapper() {
float g_device_scale_factor = 0.0f;
float GetUnforcedDeviceScaleFactor() {
+ // If the global device scale factor is initialized use it. This is to ensure
+ // we use the same scale factor across all callsites. We don't use the
+ // GetDeviceScaleFactor function here because it fires a DCHECK if the
+ // g_device_scale_factor global is 0.
+ if (g_device_scale_factor)
+ return g_device_scale_factor;
return static_cast<float>(gfx::GetDPI().width()) /
static_cast<float>(kDefaultDPIX);
}
-float GetModernUIScaleWrapper() {
- float result = 1.0f;
- typedef float(WINAPI *GetModernUIScalePtr)(VOID);
- HMODULE lib = LoadLibraryA("metro_driver.dll");
- if (lib) {
- GetModernUIScalePtr func =
- reinterpret_cast<GetModernUIScalePtr>(
- GetProcAddress(lib, "GetModernUIScale"));
- if (func)
- result = func();
- FreeLibrary(lib);
+// Duplicated from Win8.1 SDK ShellScalingApi.h
+typedef enum PROCESS_DPI_AWARENESS {
+ PROCESS_DPI_UNAWARE = 0,
+ PROCESS_SYSTEM_DPI_AWARE = 1,
+ PROCESS_PER_MONITOR_DPI_AWARE = 2
+} PROCESS_DPI_AWARENESS;
+
+typedef enum MONITOR_DPI_TYPE {
+ MDT_EFFECTIVE_DPI = 0,
+ MDT_ANGULAR_DPI = 1,
+ MDT_RAW_DPI = 2,
+ MDT_DEFAULT = MDT_EFFECTIVE_DPI
+} MONITOR_DPI_TYPE;
+
+// Win8.1 supports monitor-specific DPI scaling.
+bool SetProcessDpiAwarenessWrapper(PROCESS_DPI_AWARENESS value) {
+ typedef BOOL(WINAPI *SetProcessDpiAwarenessPtr)(PROCESS_DPI_AWARENESS);
+ SetProcessDpiAwarenessPtr set_process_dpi_awareness_func =
+ reinterpret_cast<SetProcessDpiAwarenessPtr>(
+ GetProcAddress(GetModuleHandleA("user32.dll"),
+ "SetProcessDpiAwarenessInternal"));
+ if (set_process_dpi_awareness_func) {
+ HRESULT hr = set_process_dpi_awareness_func(value);
+ if (SUCCEEDED(hr)) {
+ VLOG(1) << "SetProcessDpiAwareness succeeded.";
+ return true;
+ } else if (hr == E_ACCESSDENIED) {
+ LOG(ERROR) << "Access denied error from SetProcessDpiAwareness. "
+ "Function called twice, or manifest was used.";
+ }
}
- return result;
+ return false;
+}
+
+// This function works for Windows Vista through Win8. Win8.1 must use
+// SetProcessDpiAwareness[Wrapper]
+BOOL SetProcessDPIAwareWrapper() {
+ typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID);
+ SetProcessDPIAwarePtr set_process_dpi_aware_func =
+ reinterpret_cast<SetProcessDPIAwarePtr>(
+ GetProcAddress(GetModuleHandleA("user32.dll"),
+ "SetProcessDPIAware"));
+ return set_process_dpi_aware_func &&
+ set_process_dpi_aware_func();
+}
+
+DWORD ReadRegistryValue(HKEY root,
+ const wchar_t* base_key,
+ const wchar_t* value_name,
+ DWORD default_value) {
+ base::win::RegKey reg_key(HKEY_CURRENT_USER,
+ base_key,
+ KEY_QUERY_VALUE);
+ DWORD value;
+ if (reg_key.Valid() &&
+ reg_key.ReadValueDW(value_name, &value) == ERROR_SUCCESS) {
+ return value;
+ }
+ return default_value;
}
} // namespace
namespace gfx {
-float GetModernUIScale() {
- return GetModernUIScaleWrapper();
-}
-
void InitDeviceScaleFactor(float scale) {
DCHECK_NE(0.0f, scale);
g_device_scale_factor = scale;
@@ -91,14 +141,18 @@ float GetDPIScale() {
return 1.0;
}
+void ForceHighDPISupportForTesting(float scale) {
+ g_device_scale_factor = scale;
+}
+
bool IsHighDPIEnabled() {
+ // Flag stored in HKEY_CURRENT_USER\SOFTWARE\\Google\\Chrome\\Profile,
+ // under the DWORD value high-dpi-support.
// Default is disabled.
- if (CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kHighDPISupport)) {
- return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
- switches::kHighDPISupport).compare("1") == 0;
- }
- return false;
+ static DWORD value = ReadRegistryValue(
+ HKEY_CURRENT_USER, gfx::win::kRegistryProfilePath,
+ gfx::win::kHighDPISupportW, TRUE);
+ return value != 0;
}
bool IsInHighDPIMode() {
@@ -107,31 +161,25 @@ bool IsInHighDPIMode() {
void EnableHighDPISupport() {
if (IsHighDPIEnabled() &&
- (base::win::GetVersion() < base::win::VERSION_WIN8_1)) {
- typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID);
- SetProcessDPIAwarePtr set_process_dpi_aware_func =
- reinterpret_cast<SetProcessDPIAwarePtr>(
- GetProcAddress(GetModuleHandleA("user32.dll"),
- "SetProcessDPIAware"));
- if (set_process_dpi_aware_func)
- set_process_dpi_aware_func();
+ !SetProcessDpiAwarenessWrapper(PROCESS_SYSTEM_DPI_AWARE)) {
+ SetProcessDPIAwareWrapper();
}
}
namespace win {
+GFX_EXPORT const wchar_t kRegistryProfilePath[] =
+ L"Software\\Google\\Chrome\\Profile";
+GFX_EXPORT const wchar_t kHighDPISupportW[] = L"high-dpi-support";
+
float GetDeviceScaleFactor() {
DCHECK_NE(0.0f, g_device_scale_factor);
return g_device_scale_factor;
}
Point ScreenToDIPPoint(const Point& pixel_point) {
- static float scaling_factor =
- GetDeviceScaleFactor() > GetUnforcedDeviceScaleFactor() ?
- 1.0f / GetDeviceScaleFactor() :
- 1.0f;
return ToFlooredPoint(ScalePoint(pixel_point,
- scaling_factor));
+ 1.0f / GetDeviceScaleFactor()));
}
Point DIPToScreenPoint(const Point& dip_point) {
@@ -145,9 +193,17 @@ Rect ScreenToDIPRect(const Rect& pixel_bounds) {
}
Rect DIPToScreenRect(const Rect& dip_bounds) {
- // TODO(kevers): Switch to non-deprecated method for float to int conversions.
- return ToFlooredRectDeprecated(
- ScaleRect(dip_bounds, GetDeviceScaleFactor()));
+ // We scale the origin by the scale factor and round up via ceil. This
+ // ensures that we get the original logical origin back when we scale down.
+ // We round the size down after scaling. It may be better to round this up
+ // on the same lines as the origin.
+ // TODO(ananta)
+ // Investigate if rounding size up on the same lines as origin is workable.
+ return gfx::Rect(
+ gfx::ToCeiledPoint(gfx::ScalePoint(
+ dip_bounds.origin(), GetDeviceScaleFactor())),
+ gfx::ToFlooredSize(gfx::ScaleSize(
+ dip_bounds.size(), GetDeviceScaleFactor())));
}
Size ScreenToDIPSize(const Size& size_in_pixels) {
@@ -164,31 +220,8 @@ int GetSystemMetricsInDIP(int metric) {
GetDeviceScaleFactor() + 0.5);
}
-double GetUndocumentedDPIScale() {
- // TODO(girard): Remove this code when chrome is DPIAware.
- static double scale = -1.0;
- if (scale == -1.0) {
- scale = 1.0;
- if (!IsProcessDPIAwareWrapper()) {
- base::win::RegKey key(HKEY_CURRENT_USER,
- L"Control Panel\\Desktop\\WindowMetrics",
- KEY_QUERY_VALUE);
- if (key.Valid()) {
- DWORD value = 0;
- if (key.ReadValueDW(L"AppliedDPI", &value) == ERROR_SUCCESS) {
- scale = static_cast<double>(value) / kDefaultDPIX;
- }
- }
- }
- }
- return scale;
-}
-
-double GetUndocumentedDPITouchScale() {
- static double scale =
- (base::win::GetVersion() < base::win::VERSION_WIN8_1) ?
- GetUndocumentedDPIScale() : 1.0;
- return scale;
+bool IsDeviceScaleFactorSet() {
+ return g_device_scale_factor != 0.0f;
}
} // namespace win
diff --git a/chromium/ui/gfx/win/dpi.h b/chromium/ui/gfx/win/dpi.h
index 772944f50f9..9dcf3802456 100644
--- a/chromium/ui/gfx/win/dpi.h
+++ b/chromium/ui/gfx/win/dpi.h
@@ -22,14 +22,9 @@ GFX_EXPORT void InitDeviceScaleFactor(float scale);
GFX_EXPORT Size GetDPI();
// Gets the scale factor of the display. For example, if the display DPI is
-// 96 then the scale factor is 1.0. Note that this is the "desktop" scale, which
-// may be differnt than GetModernUIScale().
+// 96 then the scale factor is 1.0.
GFX_EXPORT float GetDPIScale();
-// Gets the scale factor of the modern (metro) UI display. Returns 1.0 for
-// unscaled or "not running on win8+"
-GFX_EXPORT float GetModernUIScale();
-
// Tests to see if the command line flag "--high-dpi-support" is set.
GFX_EXPORT bool IsHighDPIEnabled();
@@ -37,6 +32,8 @@ GFX_EXPORT bool IsInHighDPIMode();
GFX_EXPORT void EnableHighDPISupport();
+GFX_EXPORT void ForceHighDPISupportForTesting(float scale);
+
// TODO(kevers|girard): Move above methods into win namespace.
namespace win {
@@ -59,18 +56,12 @@ GFX_EXPORT Size DIPToScreenSize(const Size& dip_size);
// GetSystemMetrics for the given |metric|, then converts the result to DIP.
GFX_EXPORT int GetSystemMetricsInDIP(int metric);
-// Sometimes the OS secretly scales apps that are not DPIAware. This is not
-// visible through standard OS calls like GetWindowPos(), or through
-// GetDPIScale().
-// Returns the scale factor of the display, where 96 DPI is 1.0.
-// (Avoid this function... use GetDPIScale() instead.)
-// TODO(girard): Remove this once DPIAware is enabled - http://crbug.com/149881
-GFX_EXPORT double GetUndocumentedDPIScale();
-
-// Win7 and Win8 send touch events scaled according to the current DPI
-// scaling. Win8.1 corrects this, and sends touch events in DPI units.
-// This function returns the appropriate scaling factor for touch events.
-GFX_EXPORT double GetUndocumentedDPITouchScale();
+// Returns true if the global device scale factor has been explicitly set for
+// the process.
+GFX_EXPORT bool IsDeviceScaleFactorSet();
+
+GFX_EXPORT extern const wchar_t kRegistryProfilePath[];
+GFX_EXPORT extern const wchar_t kHighDPISupportW[];
} // namespace win
} // namespace gfx
diff --git a/chromium/ui/gfx/win/hwnd_util.cc b/chromium/ui/gfx/win/hwnd_util.cc
index fec39d4fe59..050aa9b733f 100644
--- a/chromium/ui/gfx/win/hwnd_util.cc
+++ b/chromium/ui/gfx/win/hwnd_util.cc
@@ -24,7 +24,7 @@ void AdjustWindowToFit(HWND hwnd, const RECT& bounds, bool fit_to_monitor) {
if (hmon) {
MONITORINFO mi;
mi.cbSize = sizeof(mi);
- base::win::GetMonitorInfoWrapper(hmon, &mi);
+ GetMonitorInfo(hmon, &mi);
Rect window_rect(bounds);
Rect monitor_rect(mi.rcWork);
Rect new_window_rect = window_rect;
@@ -54,23 +54,23 @@ void AdjustWindowToFit(HWND hwnd, const RECT& bounds, bool fit_to_monitor) {
MSVC_DISABLE_OPTIMIZE();
void CrashOutOfMemory() {
- LOG_GETLASTERROR(FATAL);
+ PLOG(FATAL);
}
void CrashAccessDenied() {
- LOG_GETLASTERROR(FATAL);
+ PLOG(FATAL);
}
// Crash isn't one of the ones we commonly see.
void CrashOther() {
- LOG_GETLASTERROR(FATAL);
+ PLOG(FATAL);
}
MSVC_ENABLE_OPTIMIZE();
} // namespace
-string16 GetClassName(HWND window) {
+base::string16 GetClassName(HWND window) {
// GetClassNameW will return a truncated result (properly null terminated) if
// the given buffer is not large enough. So, it is not possible to determine
// that we got the entire class name if the result is exactly equal to the
@@ -150,7 +150,7 @@ void CenterAndSizeWindow(HWND parent,
if (monitor) {
MONITORINFO mi = {0};
mi.cbSize = sizeof(mi);
- base::win::GetMonitorInfoWrapper(monitor, &mi);
+ GetMonitorInfo(monitor, &mi);
center_bounds = mi.rcWork;
} else {
NOTREACHED() << "Unable to get default monitor";
@@ -200,16 +200,17 @@ void CheckWindowCreated(HWND hwnd) {
CrashOther();
break;
}
- LOG_GETLASTERROR(FATAL);
+ PLOG(FATAL);
}
}
void ShowSystemMenu(HWND window) {
RECT rect;
GetWindowRect(window, &rect);
- Point point = Point(rect.left, rect.top);
+ Point point = Point(base::i18n::IsRTL() ? rect.right : rect.left, rect.top);
static const int kSystemMenuOffset = 10;
- point.Offset(kSystemMenuOffset, kSystemMenuOffset);
+ point.Offset(base::i18n::IsRTL() ? -kSystemMenuOffset : kSystemMenuOffset,
+ kSystemMenuOffset);
ShowSystemMenuAtPoint(window, point);
}
diff --git a/chromium/ui/gfx/win/hwnd_util.h b/chromium/ui/gfx/win/hwnd_util.h
index 472daccd82e..2afd660f5d8 100644
--- a/chromium/ui/gfx/win/hwnd_util.h
+++ b/chromium/ui/gfx/win/hwnd_util.h
@@ -15,8 +15,8 @@ class Point;
class Size;
// A version of the GetClassNameW API that returns the class name in an
-// string16. An empty result indicates a failure to get the class name.
-GFX_EXPORT string16 GetClassName(HWND hwnd);
+// base::string16. An empty result indicates a failure to get the class name.
+GFX_EXPORT base::string16 GetClassName(HWND hwnd);
// Useful for subclassing a HWND. Returns the previous window procedure.
GFX_EXPORT WNDPROC SetWindowProc(HWND hwnd, WNDPROC wndproc);
diff --git a/chromium/ui/gfx/win/msg_util.h b/chromium/ui/gfx/win/msg_util.h
new file mode 100644
index 00000000000..a5d241b1234
--- /dev/null
+++ b/chromium/ui/gfx/win/msg_util.h
@@ -0,0 +1,2283 @@
+// 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_WIN_MSG_UTIL_H_
+#define UI_GFX_WIN_MSG_UTIL_H_
+
+#include "base/logging.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/gfx/geometry/size.h"
+
+// Based on WTL version 8.0 atlcrack.h
+
+// This differs from the original atlcrack.h by removing usage of CPoint,
+// CSize, etc.
+
+///////////////////////////////////////////////////////////////////////////////
+// Message map macro for cracked handlers
+
+// Note about message maps with cracked handlers:
+// For ATL 3.0, a message map using cracked handlers MUST use BEGIN_MSG_MAP_EX.
+// For ATL 7.0 or higher, you can use BEGIN_MSG_MAP for CWindowImpl/CDialogImpl
+// derived classes,
+// but must use BEGIN_MSG_MAP_EX for classes that don't derive from
+// CWindowImpl/CDialogImpl.
+
+#define CR_BEGIN_MSG_MAP_EX(theClass) \
+ public: \
+ BOOL m_bMsgHandled; \
+ /* "handled" management for cracked handlers */ \
+ BOOL IsMsgHandled() const { return m_bMsgHandled; } \
+ void SetMsgHandled(BOOL bHandled) { m_bMsgHandled = bHandled; } \
+ BOOL ProcessWindowMessage(HWND hWnd, \
+ UINT uMsg, \
+ WPARAM wParam, \
+ LPARAM lParam, \
+ LRESULT& lResult, \
+ DWORD dwMsgMapID = 0) { \
+ BOOL bOldMsgHandled = m_bMsgHandled; \
+ BOOL bRet = _ProcessWindowMessage( \
+ hWnd, uMsg, wParam, lParam, lResult, dwMsgMapID); \
+ m_bMsgHandled = bOldMsgHandled; \
+ return bRet; \
+ } \
+ BOOL _ProcessWindowMessage(HWND hWnd, \
+ UINT uMsg, \
+ WPARAM wParam, \
+ LPARAM lParam, \
+ LRESULT& lResult, \
+ DWORD dwMsgMapID) { \
+ BOOL bHandled = TRUE; \
+ hWnd; \
+ uMsg; \
+ wParam; \
+ lParam; \
+ lResult; \
+ bHandled; \
+ switch (dwMsgMapID) { \
+ case 0:
+
+// Replacement for atlwin.h's END_MSG_MAP for removing ATL usage.
+#define CR_END_MSG_MAP() \
+ break; \
+ default: \
+ NOTREACHED() << "Invalid message map ID: " << dwMsgMapID; \
+ break; \
+ } \
+ return FALSE; \
+ }
+
+#define CR_GET_X_LPARAM(lParam) ((int)(short)LOWORD(lParam))
+#define CR_GET_Y_LPARAM(lParam) ((int)(short)HIWORD(lParam))
+
+///////////////////////////////////////////////////////////////////////////////
+// Standard Windows message macros
+
+// int OnCreate(LPCREATESTRUCT lpCreateStruct)
+#define CR_MSG_WM_CREATE(func) \
+ if (uMsg == WM_CREATE) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnInitDialog(CWindow wndFocus, LPARAM lInitParam)
+#define CR_MSG_WM_INITDIALOG(func) \
+ if (uMsg == WM_INITDIALOG) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HWND)wParam, lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnCopyData(CWindow wnd, PCOPYDATASTRUCT pCopyDataStruct)
+#define CR_MSG_WM_COPYDATA(func) \
+ if (uMsg == WM_COPYDATA) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HWND)wParam, (PCOPYDATASTRUCT)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDestroy()
+#define CR_MSG_WM_DESTROY(func) \
+ if (uMsg == WM_DESTROY) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMove(CPoint ptPos)
+#define CR_MSG_WM_MOVE(func) \
+ if (uMsg == WM_MOVE) { \
+ SetMsgHandled(TRUE); \
+ func(gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSize(UINT nType, gfx::Size size)
+#define CR_MSG_WM_SIZE(func) \
+ if (uMsg == WM_SIZE) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Size(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnActivate(UINT nState, BOOL bMinimized, CWindow wndOther)
+#define CR_MSG_WM_ACTIVATE(func) \
+ if (uMsg == WM_ACTIVATE) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)LOWORD(wParam), (BOOL)HIWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSetFocus(CWindow wndOld)
+#define CR_MSG_WM_SETFOCUS(func) \
+ if (uMsg == WM_SETFOCUS) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnKillFocus(CWindow wndFocus)
+#define CR_MSG_WM_KILLFOCUS(func) \
+ if (uMsg == WM_KILLFOCUS) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnEnable(BOOL bEnable)
+#define CR_MSG_WM_ENABLE(func) \
+ if (uMsg == WM_ENABLE) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPaint(CDCHandle dc)
+#define CR_MSG_WM_PAINT(func) \
+ if (uMsg == WM_PAINT) { \
+ SetMsgHandled(TRUE); \
+ func((HDC)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnClose()
+#define CR_MSG_WM_CLOSE(func) \
+ if (uMsg == WM_CLOSE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnQueryEndSession(UINT nSource, UINT uLogOff)
+#define CR_MSG_WM_QUERYENDSESSION(func) \
+ if (uMsg == WM_QUERYENDSESSION) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam, (UINT)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnQueryOpen()
+#define CR_MSG_WM_QUERYOPEN(func) \
+ if (uMsg == WM_QUERYOPEN) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnEraseBkgnd(CDCHandle dc)
+#define CR_MSG_WM_ERASEBKGND(func) \
+ if (uMsg == WM_ERASEBKGND) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysColorChange()
+#define CR_MSG_WM_SYSCOLORCHANGE(func) \
+ if (uMsg == WM_SYSCOLORCHANGE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnEndSession(BOOL bEnding, UINT uLogOff)
+#define CR_MSG_WM_ENDSESSION(func) \
+ if (uMsg == WM_ENDSESSION) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam, (UINT)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnShowWindow(BOOL bShow, UINT nStatus)
+#define CR_MSG_WM_SHOWWINDOW(func) \
+ if (uMsg == WM_SHOWWINDOW) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam, (int)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorEdit(CDCHandle dc, CEdit edit)
+#define CR_MSG_WM_CTLCOLOREDIT(func) \
+ if (uMsg == WM_CTLCOLOREDIT) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorListBox(CDCHandle dc, CListBox listBox)
+#define CR_MSG_WM_CTLCOLORLISTBOX(func) \
+ if (uMsg == WM_CTLCOLORLISTBOX) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorBtn(CDCHandle dc, CButton button)
+#define CR_MSG_WM_CTLCOLORBTN(func) \
+ if (uMsg == WM_CTLCOLORBTN) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorDlg(CDCHandle dc, CWindow wnd)
+#define CR_MSG_WM_CTLCOLORDLG(func) \
+ if (uMsg == WM_CTLCOLORDLG) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorScrollBar(CDCHandle dc, CScrollBar scrollBar)
+#define CR_MSG_WM_CTLCOLORSCROLLBAR(func) \
+ if (uMsg == WM_CTLCOLORSCROLLBAR) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnCtlColorStatic(CDCHandle dc, CStatic wndStatic)
+#define CR_MSG_WM_CTLCOLORSTATIC(func) \
+ if (uMsg == WM_CTLCOLORSTATIC) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
+#define CR_MSG_WM_SETTINGCHANGE(func) \
+ if (uMsg == WM_SETTINGCHANGE) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPCTSTR)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDevModeChange(LPCTSTR lpDeviceName)
+#define CR_MSG_WM_DEVMODECHANGE(func) \
+ if (uMsg == WM_DEVMODECHANGE) { \
+ SetMsgHandled(TRUE); \
+ func((LPCTSTR)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnActivateApp(BOOL bActive, DWORD dwThreadID)
+#define CR_MSG_WM_ACTIVATEAPP(func) \
+ if (uMsg == WM_ACTIVATEAPP) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam, (DWORD)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnFontChange()
+#define CR_MSG_WM_FONTCHANGE(func) \
+ if (uMsg == WM_FONTCHANGE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnTimeChange()
+#define CR_MSG_WM_TIMECHANGE(func) \
+ if (uMsg == WM_TIMECHANGE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCancelMode()
+#define CR_MSG_WM_CANCELMODE(func) \
+ if (uMsg == WM_CANCELMODE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnSetCursor(CWindow wnd, UINT nHitTest, UINT message)
+#define CR_MSG_WM_SETCURSOR(func) \
+ if (uMsg == WM_SETCURSOR) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ (HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnMouseActivate(CWindow wndTopLevel, UINT nHitTest, UINT message)
+#define CR_MSG_WM_MOUSEACTIVATE(func) \
+ if (uMsg == WM_MOUSEACTIVATE) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ (HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnChildActivate()
+#define CR_MSG_WM_CHILDACTIVATE(func) \
+ if (uMsg == WM_CHILDACTIVATE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnGetMinMaxInfo(LPMINMAXINFO lpMMI)
+#define CR_MSG_WM_GETMINMAXINFO(func) \
+ if (uMsg == WM_GETMINMAXINFO) { \
+ SetMsgHandled(TRUE); \
+ func((LPMINMAXINFO)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnIconEraseBkgnd(CDCHandle dc)
+#define CR_MSG_WM_ICONERASEBKGND(func) \
+ if (uMsg == WM_ICONERASEBKGND) { \
+ SetMsgHandled(TRUE); \
+ func((HDC)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSpoolerStatus(UINT nStatus, UINT nJobs)
+#define CR_MSG_WM_SPOOLERSTATUS(func) \
+ if (uMsg == WM_SPOOLERSTATUS) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (UINT)LOWORD(lParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
+#define CR_MSG_WM_DRAWITEM(func) \
+ if (uMsg == WM_DRAWITEM) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
+#define CR_MSG_WM_MEASUREITEM(func) \
+ if (uMsg == WM_MEASUREITEM) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPMEASUREITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDeleteItem(int nIDCtl, LPDELETEITEMSTRUCT lpDeleteItemStruct)
+#define CR_MSG_WM_DELETEITEM(func) \
+ if (uMsg == WM_DELETEITEM) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPDELETEITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnCharToItem(UINT nChar, UINT nIndex, CListBox listBox)
+#define CR_MSG_WM_CHARTOITEM(func) \
+ if (uMsg == WM_CHARTOITEM) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ (UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnVKeyToItem(UINT nKey, UINT nIndex, CListBox listBox)
+#define CR_MSG_WM_VKEYTOITEM(func) \
+ if (uMsg == WM_VKEYTOITEM) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ (UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HCURSOR OnQueryDragIcon()
+#define CR_MSG_WM_QUERYDRAGICON(func) \
+ if (uMsg == WM_QUERYDRAGICON) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnCompareItem(int nIDCtl, LPCOMPAREITEMSTRUCT lpCompareItemStruct)
+#define CR_MSG_WM_COMPAREITEM(func) \
+ if (uMsg == WM_COMPAREITEM) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam, (LPCOMPAREITEMSTRUCT)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCompacting(UINT nCpuTime)
+#define CR_MSG_WM_COMPACTING(func) \
+ if (uMsg == WM_COMPACTING) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnNcCreate(LPCREATESTRUCT lpCreateStruct)
+#define CR_MSG_WM_NCCREATE(func) \
+ if (uMsg == WM_NCCREATE) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcDestroy()
+#define CR_MSG_WM_NCDESTROY(func) \
+ if (uMsg == WM_NCDESTROY) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNcCalcSize(BOOL bCalcValidRects, LPARAM lParam)
+#define CR_MSG_WM_NCCALCSIZE(func) \
+ if (uMsg == WM_NCCALCSIZE) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((BOOL)wParam, lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// UINT OnNcHitTest(gfx::Point point)
+#define CR_MSG_WM_NCHITTEST(func) \
+ if (uMsg == WM_NCHITTEST) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcPaint(CRgn rgn)
+#define CR_MSG_WM_NCPAINT(func) \
+ if (uMsg == WM_NCPAINT) { \
+ SetMsgHandled(TRUE); \
+ func((HRGN)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnNcActivate(BOOL bActive)
+#define CR_MSG_WM_NCACTIVATE(func) \
+ if (uMsg == WM_NCACTIVATE) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((BOOL)wParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// UINT OnGetDlgCode(LPMSG lpMsg)
+#define CR_MSG_WM_GETDLGCODE(func) \
+ if (uMsg == WM_GETDLGCODE) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((LPMSG)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcMouseMove(UINT nHitTest, gfx::Point point)
+#define CR_MSG_WM_NCMOUSEMOVE(func) \
+ if (uMsg == WM_NCMOUSEMOVE) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcLButtonDown(UINT nHitTest, gfx::Point point)
+#define CR_MSG_WM_NCLBUTTONDOWN(func) \
+ if (uMsg == WM_NCLBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcLButtonUp(UINT nHitTest, gfx::Point point)
+#define CR_MSG_WM_NCLBUTTONUP(func) \
+ if (uMsg == WM_NCLBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcLButtonDblClk(UINT nHitTest, gfx::Point point)
+#define CR_MSG_WM_NCLBUTTONDBLCLK(func) \
+ if (uMsg == WM_NCLBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcRButtonDown(UINT nHitTest, gfx::Point point)
+#define CR_MSG_WM_NCRBUTTONDOWN(func) \
+ if (uMsg == WM_NCRBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcRButtonUp(UINT nHitTest, gfx::Point point)
+#define CR_MSG_WM_NCRBUTTONUP(func) \
+ if (uMsg == WM_NCRBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcRButtonDblClk(UINT nHitTest, CPoint point)
+#define CR_MSG_WM_NCRBUTTONDBLCLK(func) \
+ if (uMsg == WM_NCRBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcMButtonDown(UINT nHitTest, CPoint point)
+#define CR_MSG_WM_NCMBUTTONDOWN(func) \
+ if (uMsg == WM_NCMBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcMButtonUp(UINT nHitTest, CPoint point)
+#define CR_MSG_WM_NCMBUTTONUP(func) \
+ if (uMsg == WM_NCMBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNcMButtonDblClk(UINT nHitTest, CPoint point)
+#define CR_MSG_WM_NCMBUTTONDBLCLK(func) \
+ if (uMsg == WM_NCMBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_KEYDOWN(func) \
+ if (uMsg == WM_KEYDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_KEYUP(func) \
+ if (uMsg == WM_KEYUP) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_CHAR(func) \
+ if (uMsg == WM_CHAR) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_DEADCHAR(func) \
+ if (uMsg == WM_DEADCHAR) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_SYSKEYDOWN(func) \
+ if (uMsg == WM_SYSKEYDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_SYSKEYUP(func) \
+ if (uMsg == WM_SYSKEYUP) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_SYSCHAR(func) \
+ if (uMsg == WM_SYSCHAR) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysDeadChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_SYSDEADCHAR(func) \
+ if (uMsg == WM_SYSDEADCHAR) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSysCommand(UINT nID, LPARAM lParam)
+#define CR_MSG_WM_SYSCOMMAND(func) \
+ if (uMsg == WM_SYSCOMMAND) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnTCard(UINT idAction, DWORD dwActionData)
+#define CR_MSG_WM_TCARD(func) \
+ if (uMsg == WM_TCARD) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (DWORD)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnTimer(UINT_PTR nIDEvent)
+#define CR_MSG_WM_TIMER(func) \
+ if (uMsg == WM_TIMER) { \
+ SetMsgHandled(TRUE); \
+ func((UINT_PTR)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)
+#define CR_MSG_WM_HSCROLL(func) \
+ if (uMsg == WM_HSCROLL) { \
+ SetMsgHandled(TRUE); \
+ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)
+#define CR_MSG_WM_VSCROLL(func) \
+ if (uMsg == WM_VSCROLL) { \
+ SetMsgHandled(TRUE); \
+ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnInitMenu(CMenu menu)
+#define CR_MSG_WM_INITMENU(func) \
+ if (uMsg == WM_INITMENU) { \
+ SetMsgHandled(TRUE); \
+ func((HMENU)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnInitMenuPopup(CMenu menuPopup, UINT nIndex, BOOL bSysMenu)
+#define CR_MSG_WM_INITMENUPOPUP(func) \
+ if (uMsg == WM_INITMENUPOPUP) { \
+ SetMsgHandled(TRUE); \
+ func((HMENU)wParam, (UINT)LOWORD(lParam), (BOOL)HIWORD(lParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMenuSelect(UINT nItemID, UINT nFlags, CMenu menu)
+#define CR_MSG_WM_MENUSELECT(func) \
+ if (uMsg == WM_MENUSELECT) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HMENU)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnMenuChar(UINT nChar, UINT nFlags, CMenu menu)
+#define CR_MSG_WM_MENUCHAR(func) \
+ if (uMsg == WM_MENUCHAR) { \
+ SetMsgHandled(TRUE); \
+ lResult = \
+ func((TCHAR)LOWORD(wParam), (UINT)HIWORD(wParam), (HMENU)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotify(int idCtrl, LPNMHDR pnmh)
+#define CR_MSG_WM_NOTIFY(func) \
+ if (uMsg == WM_NOTIFY) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((int)wParam, (LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnEnterIdle(UINT nWhy, CWindow wndWho)
+#define CR_MSG_WM_ENTERIDLE(func) \
+ if (uMsg == WM_ENTERIDLE) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMouseMove(UINT nFlags, CPoint point)
+#define CR_MSG_WM_MOUSEMOVE(func) \
+ if (uMsg == WM_MOUSEMOVE) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
+#define CR_MSG_WM_MOUSEWHEEL(func) \
+ if (uMsg == WM_MOUSEWHEEL) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ (UINT)LOWORD(wParam), \
+ (short)HIWORD(wParam), \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnLButtonDown(UINT nFlags, CPoint point)
+#define CR_MSG_WM_LBUTTONDOWN(func) \
+ if (uMsg == WM_LBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnLButtonUp(UINT nFlags, CPoint point)
+#define CR_MSG_WM_LBUTTONUP(func) \
+ if (uMsg == WM_LBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnLButtonDblClk(UINT nFlags, CPoint point)
+#define CR_MSG_WM_LBUTTONDBLCLK(func) \
+ if (uMsg == WM_LBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRButtonDown(UINT nFlags, CPoint point)
+#define CR_MSG_WM_RBUTTONDOWN(func) \
+ if (uMsg == WM_RBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRButtonUp(UINT nFlags, CPoint point)
+#define CR_MSG_WM_RBUTTONUP(func) \
+ if (uMsg == WM_RBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRButtonDblClk(UINT nFlags, CPoint point)
+#define CR_MSG_WM_RBUTTONDBLCLK(func) \
+ if (uMsg == WM_RBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMButtonDown(UINT nFlags, CPoint point)
+#define CR_MSG_WM_MBUTTONDOWN(func) \
+ if (uMsg == WM_MBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMButtonUp(UINT nFlags, CPoint point)
+#define CR_MSG_WM_MBUTTONUP(func) \
+ if (uMsg == WM_MBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMButtonDblClk(UINT nFlags, CPoint point)
+#define CR_MSG_WM_MBUTTONDBLCLK(func) \
+ if (uMsg == WM_MBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnParentNotify(UINT message, UINT nChildID, LPARAM lParam)
+#define CR_MSG_WM_PARENTNOTIFY(func) \
+ if (uMsg == WM_PARENTNOTIFY) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMDIActivate(CWindow wndActivate, CWindow wndDeactivate)
+#define CR_MSG_WM_MDIACTIVATE(func) \
+ if (uMsg == WM_MDIACTIVATE) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRenderFormat(UINT nFormat)
+#define CR_MSG_WM_RENDERFORMAT(func) \
+ if (uMsg == WM_RENDERFORMAT) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRenderAllFormats()
+#define CR_MSG_WM_RENDERALLFORMATS(func) \
+ if (uMsg == WM_RENDERALLFORMATS) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDestroyClipboard()
+#define CR_MSG_WM_DESTROYCLIPBOARD(func) \
+ if (uMsg == WM_DESTROYCLIPBOARD) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDrawClipboard()
+#define CR_MSG_WM_DRAWCLIPBOARD(func) \
+ if (uMsg == WM_DRAWCLIPBOARD) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPaintClipboard(CWindow wndViewer, const LPPAINTSTRUCT lpPaintStruct)
+#define CR_MSG_WM_PAINTCLIPBOARD(func) \
+ if (uMsg == WM_PAINTCLIPBOARD) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (const LPPAINTSTRUCT)::GlobalLock((HGLOBAL)lParam)); \
+ ::GlobalUnlock((HGLOBAL)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnVScrollClipboard(CWindow wndViewer, UINT nSBCode, UINT nPos)
+#define CR_MSG_WM_VSCROLLCLIPBOARD(func) \
+ if (uMsg == WM_VSCROLLCLIPBOARD) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnContextMenu(CWindow wnd, CPoint point)
+#define CR_MSG_WM_CONTEXTMENU(func) \
+ if (uMsg == WM_CONTEXTMENU) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSizeClipboard(CWindow wndViewer, const LPRECT lpRect)
+#define CR_MSG_WM_SIZECLIPBOARD(func) \
+ if (uMsg == WM_SIZECLIPBOARD) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (const LPRECT)::GlobalLock((HGLOBAL)lParam)); \
+ ::GlobalUnlock((HGLOBAL)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnAskCbFormatName(UINT nMaxCount, LPTSTR lpszString)
+#define CR_MSG_WM_ASKCBFORMATNAME(func) \
+ if (uMsg == WM_ASKCBFORMATNAME) { \
+ SetMsgHandled(TRUE); \
+ func((DWORD)wParam, (LPTSTR)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnChangeCbChain(CWindow wndRemove, CWindow wndAfter)
+#define CR_MSG_WM_CHANGECBCHAIN(func) \
+ if (uMsg == WM_CHANGECBCHAIN) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnHScrollClipboard(CWindow wndViewer, UINT nSBCode, UINT nPos)
+#define CR_MSG_WM_HSCROLLCLIPBOARD(func) \
+ if (uMsg == WM_HSCROLLCLIPBOARD) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnQueryNewPalette()
+#define CR_MSG_WM_QUERYNEWPALETTE(func) \
+ if (uMsg == WM_QUERYNEWPALETTE) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPaletteChanged(CWindow wndFocus)
+#define CR_MSG_WM_PALETTECHANGED(func) \
+ if (uMsg == WM_PALETTECHANGED) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPaletteIsChanging(CWindow wndPalChg)
+#define CR_MSG_WM_PALETTEISCHANGING(func) \
+ if (uMsg == WM_PALETTEISCHANGING) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDropFiles(HDROP hDropInfo)
+#define CR_MSG_WM_DROPFILES(func) \
+ if (uMsg == WM_DROPFILES) { \
+ SetMsgHandled(TRUE); \
+ func((HDROP)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnWindowPosChanging(LPWINDOWPOS lpWndPos)
+#define CR_MSG_WM_WINDOWPOSCHANGING(func) \
+ if (uMsg == WM_WINDOWPOSCHANGING) { \
+ SetMsgHandled(TRUE); \
+ func((LPWINDOWPOS)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnWindowPosChanged(LPWINDOWPOS lpWndPos)
+#define CR_MSG_WM_WINDOWPOSCHANGED(func) \
+ if (uMsg == WM_WINDOWPOSCHANGED) { \
+ SetMsgHandled(TRUE); \
+ func((LPWINDOWPOS)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnExitMenuLoop(BOOL fIsTrackPopupMenu)
+#define CR_MSG_WM_EXITMENULOOP(func) \
+ if (uMsg == WM_EXITMENULOOP) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnEnterMenuLoop(BOOL fIsTrackPopupMenu)
+#define CR_MSG_WM_ENTERMENULOOP(func) \
+ if (uMsg == WM_ENTERMENULOOP) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnStyleChanged(int nStyleType, LPSTYLESTRUCT lpStyleStruct)
+#define CR_MSG_WM_STYLECHANGED(func) \
+ if (uMsg == WM_STYLECHANGED) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPSTYLESTRUCT)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnStyleChanging(int nStyleType, LPSTYLESTRUCT lpStyleStruct)
+#define CR_MSG_WM_STYLECHANGING(func) \
+ if (uMsg == WM_STYLECHANGING) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPSTYLESTRUCT)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSizing(UINT fwSide, LPRECT pRect)
+#define CR_MSG_WM_SIZING(func) \
+ if (uMsg == WM_SIZING) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPRECT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMoving(UINT fwSide, LPRECT pRect)
+#define CR_MSG_WM_MOVING(func) \
+ if (uMsg == WM_MOVING) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPRECT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCaptureChanged(CWindow wnd)
+#define CR_MSG_WM_CAPTURECHANGED(func) \
+ if (uMsg == WM_CAPTURECHANGED) { \
+ SetMsgHandled(TRUE); \
+ func((HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnDeviceChange(UINT nEventType, DWORD dwData)
+#define CR_MSG_WM_DEVICECHANGE(func) \
+ if (uMsg == WM_DEVICECHANGE) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam, (DWORD)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCommand(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define CR_MSG_WM_COMMAND(func) \
+ if (uMsg == WM_COMMAND) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDisplayChange(UINT uBitsPerPixel, gfx::Size sizeScreen)
+#define CR_MSG_WM_DISPLAYCHANGE(func) \
+ if (uMsg == WM_DISPLAYCHANGE) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, \
+ gfx::Size(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnEnterSizeMove()
+#define CR_MSG_WM_ENTERSIZEMOVE(func) \
+ if (uMsg == WM_ENTERSIZEMOVE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnExitSizeMove()
+#define CR_MSG_WM_EXITSIZEMOVE(func) \
+ if (uMsg == WM_EXITSIZEMOVE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HFONT OnGetFont()
+#define CR_MSG_WM_GETFONT(func) \
+ if (uMsg == WM_GETFONT) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnGetHotKey()
+#define CR_MSG_WM_GETHOTKEY(func) \
+ if (uMsg == WM_GETHOTKEY) { \
+ SetMsgHandled(TRUE); \
+ lResult = func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HICON OnGetIcon()
+#define CR_MSG_WM_GETICON(func) \
+ if (uMsg == WM_GETICON) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnGetText(int cchTextMax, LPTSTR lpszText)
+#define CR_MSG_WM_GETTEXT(func) \
+ if (uMsg == WM_GETTEXT) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((int)wParam, (LPTSTR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnGetTextLength()
+#define CR_MSG_WM_GETTEXTLENGTH(func) \
+ if (uMsg == WM_GETTEXTLENGTH) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnHelp(LPHELPINFO lpHelpInfo)
+#define CR_MSG_WM_HELP(func) \
+ if (uMsg == WM_HELP) { \
+ SetMsgHandled(TRUE); \
+ func((LPHELPINFO)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnHotKey(int nHotKeyID, UINT uModifiers, UINT uVirtKey)
+#define CR_MSG_WM_HOTKEY(func) \
+ if (uMsg == WM_HOTKEY) { \
+ SetMsgHandled(TRUE); \
+ func((int)wParam, (UINT)LOWORD(lParam), (UINT)HIWORD(lParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnInputLangChange(DWORD dwCharSet, HKL hKbdLayout)
+#define CR_MSG_WM_INPUTLANGCHANGE(func) \
+ if (uMsg == WM_INPUTLANGCHANGE) { \
+ SetMsgHandled(TRUE); \
+ func((DWORD)wParam, (HKL)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnInputLangChangeRequest(BOOL bSysCharSet, HKL hKbdLayout)
+#define CR_MSG_WM_INPUTLANGCHANGEREQUEST(func) \
+ if (uMsg == WM_INPUTLANGCHANGEREQUEST) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam, (HKL)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNextDlgCtl(BOOL bHandle, WPARAM wCtlFocus)
+#define CR_MSG_WM_NEXTDLGCTL(func) \
+ if (uMsg == WM_NEXTDLGCTL) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)LOWORD(lParam), wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNextMenu(int nVirtKey, LPMDINEXTMENU lpMdiNextMenu)
+#define CR_MSG_WM_NEXTMENU(func) \
+ if (uMsg == WM_NEXTMENU) { \
+ SetMsgHandled(TRUE); \
+ func((int)wParam, (LPMDINEXTMENU)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnNotifyFormat(CWindow wndFrom, int nCommand)
+#define CR_MSG_WM_NOTIFYFORMAT(func) \
+ if (uMsg == WM_NOTIFYFORMAT) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HWND)wParam, (int)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// BOOL OnPowerBroadcast(DWORD dwPowerEvent, DWORD dwData)
+#define CR_MSG_WM_POWERBROADCAST(func) \
+ if (uMsg == WM_POWERBROADCAST) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((DWORD)wParam, (DWORD)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPrint(CDCHandle dc, UINT uFlags)
+#define CR_MSG_WM_PRINT(func) \
+ if (uMsg == WM_PRINT) { \
+ SetMsgHandled(TRUE); \
+ func((HDC)wParam, (UINT)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPrintClient(CDCHandle dc, UINT uFlags)
+#define CR_MSG_WM_PRINTCLIENT(func) \
+ if (uMsg == WM_PRINTCLIENT) { \
+ SetMsgHandled(TRUE); \
+ func((HDC)wParam, (UINT)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnRasDialEvent(RASCONNSTATE rasconnstate, DWORD dwError)
+#define CR_MSG_WM_RASDIALEVENT(func) \
+ if (uMsg == WM_RASDIALEVENT) { \
+ SetMsgHandled(TRUE); \
+ func((RASCONNSTATE)wParam, (DWORD)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSetFont(CFont font, BOOL bRedraw)
+#define CR_MSG_WM_SETFONT(func) \
+ if (uMsg == WM_SETFONT) { \
+ SetMsgHandled(TRUE); \
+ func((HFONT)wParam, (BOOL)LOWORD(lParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnSetHotKey(int nVirtKey, UINT uFlags)
+#define CR_MSG_WM_SETHOTKEY(func) \
+ if (uMsg == WM_SETHOTKEY) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((int)LOBYTE(LOWORD(wParam)), \
+ (UINT)HIBYTE(LOWORD(wParam))); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HICON OnSetIcon(UINT uType, HICON hIcon)
+#define CR_MSG_WM_SETICON(func) \
+ if (uMsg == WM_SETICON) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam, (HICON)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnSetRedraw(BOOL bRedraw)
+#define CR_MSG_WM_SETREDRAW(func) \
+ if (uMsg == WM_SETREDRAW) { \
+ SetMsgHandled(TRUE); \
+ func((BOOL)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnSetText(LPCTSTR lpstrText)
+#define CR_MSG_WM_SETTEXT(func) \
+ if (uMsg == WM_SETTEXT) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((LPCTSTR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnUserChanged()
+#define CR_MSG_WM_USERCHANGED(func) \
+ if (uMsg == WM_USERCHANGED) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// New NT4 & NT5 messages
+
+#if (_WIN32_WINNT >= 0x0400)
+
+// void OnMouseHover(WPARAM wParam, CPoint ptPos)
+#define CR_MSG_WM_MOUSEHOVER(func) \
+ if (uMsg == WM_MOUSEHOVER) { \
+ SetMsgHandled(TRUE); \
+ func(wParam, \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMouseLeave()
+#define CR_MSG_WM_MOUSELEAVE(func) \
+ if (uMsg == WM_MOUSELEAVE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+#endif /* _WIN32_WINNT >= 0x0400 */
+
+#if (WINVER >= 0x0500)
+
+// void OnMenuRButtonUp(WPARAM wParam, CMenu menu)
+#define CR_MSG_WM_MENURBUTTONUP(func) \
+ if (uMsg == WM_MENURBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func(wParam, (HMENU)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnMenuDrag(WPARAM wParam, CMenu menu)
+#define CR_MSG_WM_MENUDRAG(func) \
+ if (uMsg == WM_MENUDRAG) { \
+ SetMsgHandled(TRUE); \
+ lResult = func(wParam, (HMENU)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnMenuGetObject(PMENUGETOBJECTINFO info)
+#define CR_MSG_WM_MENUGETOBJECT(func) \
+ if (uMsg == WM_MENUGETOBJECT) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((PMENUGETOBJECTINFO)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnUnInitMenuPopup(UINT nID, CMenu menu)
+#define CR_MSG_WM_UNINITMENUPOPUP(func) \
+ if (uMsg == WM_UNINITMENUPOPUP) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(lParam), (HMENU)wParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnMenuCommand(WPARAM nIndex, CMenu menu)
+#define CR_MSG_WM_MENUCOMMAND(func) \
+ if (uMsg == WM_MENUCOMMAND) { \
+ SetMsgHandled(TRUE); \
+ func(wParam, (HMENU)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+#endif /* WINVER >= 0x0500 */
+
+#if (_WIN32_WINNT >= 0x0500)
+
+// BOOL OnAppCommand(CWindow wndFocus, short cmd, WORD uDevice, int dwKeys)
+#define CR_MSG_WM_APPCOMMAND(func) \
+ if (uMsg == WM_APPCOMMAND) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HWND)wParam, \
+ GET_APPCOMMAND_LPARAM(lParam), \
+ GET_DEVICE_LPARAM(lParam), \
+ GET_KEYSTATE_LPARAM(lParam)); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNCXButtonDown(int fwButton, short nHittest, CPoint ptPos)
+#define CR_MSG_WM_NCXBUTTONDOWN(func) \
+ if (uMsg == WM_NCXBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), \
+ GET_NCHITTEST_WPARAM(wParam), \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNCXButtonUp(int fwButton, short nHittest, CPoint ptPos)
+#define CR_MSG_WM_NCXBUTTONUP(func) \
+ if (uMsg == WM_NCXBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), \
+ GET_NCHITTEST_WPARAM(wParam), \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnNCXButtonDblClk(int fwButton, short nHittest, CPoint ptPos)
+#define CR_MSG_WM_NCXBUTTONDBLCLK(func) \
+ if (uMsg == WM_NCXBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), \
+ GET_NCHITTEST_WPARAM(wParam), \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnXButtonDown(int fwButton, int dwKeys, CPoint ptPos)
+#define CR_MSG_WM_XBUTTONDOWN(func) \
+ if (uMsg == WM_XBUTTONDOWN) { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), \
+ GET_KEYSTATE_WPARAM(wParam), \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnXButtonUp(int fwButton, int dwKeys, CPoint ptPos)
+#define CR_MSG_WM_XBUTTONUP(func) \
+ if (uMsg == WM_XBUTTONUP) { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), \
+ GET_KEYSTATE_WPARAM(wParam), \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnXButtonDblClk(int fwButton, int dwKeys, CPoint ptPos)
+#define CR_MSG_WM_XBUTTONDBLCLK(func) \
+ if (uMsg == WM_XBUTTONDBLCLK) { \
+ SetMsgHandled(TRUE); \
+ func(GET_XBUTTON_WPARAM(wParam), \
+ GET_KEYSTATE_WPARAM(wParam), \
+ gfx::Point(CR_GET_X_LPARAM(lParam), CR_GET_Y_LPARAM(lParam))); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnChangeUIState(WORD nAction, WORD nState)
+#define CR_MSG_WM_CHANGEUISTATE(func) \
+ if (uMsg == WM_CHANGEUISTATE) { \
+ SetMsgHandled(TRUE); \
+ func(LOWORD(wParam), HIWORD(wParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnUpdateUIState(WORD nAction, WORD nState)
+#define CR_MSG_WM_UPDATEUISTATE(func) \
+ if (uMsg == WM_UPDATEUISTATE) { \
+ SetMsgHandled(TRUE); \
+ func(LOWORD(wParam), HIWORD(wParam)); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnQueryUIState()
+#define CR_MSG_WM_QUERYUISTATE(func) \
+ if (uMsg == WM_QUERYUISTATE) { \
+ SetMsgHandled(TRUE); \
+ lResult = func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+#endif // (_WIN32_WINNT >= 0x0500)
+
+#if (_WIN32_WINNT >= 0x0501)
+
+// void OnInput(WPARAM RawInputCode, HRAWINPUT hRawInput)
+#define CR_MSG_WM_INPUT(func) \
+ if (uMsg == WM_INPUT) { \
+ SetMsgHandled(TRUE); \
+ func(GET_RAWINPUT_CODE_WPARAM(wParam), (HRAWINPUT)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnUniChar(TCHAR nChar, UINT nRepCnt, UINT nFlags)
+#define CR_MSG_WM_UNICHAR(func) \
+ if (uMsg == WM_UNICHAR) { \
+ SetMsgHandled(TRUE); \
+ func((TCHAR)wParam, \
+ (UINT)lParam & 0xFFFF, \
+ (UINT)((lParam & 0xFFFF0000) >> 16)); \
+ if (IsMsgHandled()) { \
+ lResult = (wParam == UNICODE_NOCHAR) ? TRUE : FALSE; \
+ return TRUE; \
+ } \
+ }
+
+// void OnWTSSessionChange(WPARAM nStatusCode, PWTSSESSION_NOTIFICATION
+// nSessionID)
+#define CR_MSG_WM_WTSSESSION_CHANGE(func) \
+ if (uMsg == WM_WTSSESSION_CHANGE) { \
+ SetMsgHandled(TRUE); \
+ func(wParam, (PWTSSESSION_NOTIFICATION)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// OnThemeChanged()
+#define CR_MSG_WM_THEMECHANGED(func) \
+ if (uMsg == WM_THEMECHANGED) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+#endif /* _WIN32_WINNT >= 0x0501 */
+
+///////////////////////////////////////////////////////////////////////////////
+// ATL defined messages
+
+// BOOL OnForwardMsg(LPMSG Msg, DWORD nUserData)
+#define CR_MSG_WM_FORWARDMSG(func) \
+ if (uMsg == WM_FORWARDMSG) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((LPMSG)lParam, (DWORD)wParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Dialog specific messages
+
+// LRESULT OnDMGetDefID()
+#define MSG_DM_GETDEFID(func) \
+ if (uMsg == DM_GETDEFID) { \
+ SetMsgHandled(TRUE); \
+ lResult = func(); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDMSetDefID(UINT DefID)
+#define MSG_DM_SETDEFID(func) \
+ if (uMsg == DM_SETDEFID) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnDMReposition()
+#define MSG_DM_REPOSITION(func) \
+ if (uMsg == DM_REPOSITION) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Reflected messages
+
+// void OnReflectedCommand(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define MSG_OCM_COMMAND(func) \
+ if (uMsg == OCM_COMMAND) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotify(int idCtrl, LPNMHDR pnmh)
+#define MSG_OCM_NOTIFY(func) \
+ if (uMsg == OCM_NOTIFY) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((int)wParam, (LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedParentNotify(UINT message, UINT nChildID, LPARAM lParam)
+#define MSG_OCM_PARENTNOTIFY(func) \
+ if (uMsg == OCM_PARENTNOTIFY) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)LOWORD(wParam), (UINT)HIWORD(wParam), lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
+#define MSG_OCM_DRAWITEM(func) \
+ if (uMsg == OCM_DRAWITEM) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPDRAWITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT
+// lpMeasureItemStruct)
+#define MSG_OCM_MEASUREITEM(func) \
+ if (uMsg == OCM_MEASUREITEM) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPMEASUREITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnReflectedCompareItem(int nIDCtl, LPCOMPAREITEMSTRUCT
+// lpCompareItemStruct)
+#define MSG_OCM_COMPAREITEM(func) \
+ if (uMsg == OCM_COMPAREITEM) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((UINT)wParam, (LPCOMPAREITEMSTRUCT)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedDeleteItem(int nIDCtl, LPDELETEITEMSTRUCT lpDeleteItemStruct)
+#define MSG_OCM_DELETEITEM(func) \
+ if (uMsg == OCM_DELETEITEM) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)wParam, (LPDELETEITEMSTRUCT)lParam); \
+ lResult = TRUE; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnReflectedVKeyToItem(UINT nKey, UINT nIndex, CListBox listBox)
+#define MSG_OCM_VKEYTOITEM(func) \
+ if (uMsg == OCM_VKEYTOITEM) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ (UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// int OnReflectedCharToItem(UINT nChar, UINT nIndex, CListBox listBox)
+#define MSG_OCM_CHARTOITEM(func) \
+ if (uMsg == OCM_CHARTOITEM) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func( \
+ (UINT)LOWORD(wParam), (UINT)HIWORD(wParam), (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedHScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)
+#define MSG_OCM_HSCROLL(func) \
+ if (uMsg == OCM_HSCROLL) { \
+ SetMsgHandled(TRUE); \
+ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedVScroll(UINT nSBCode, UINT nPos, CScrollBar pScrollBar)
+#define MSG_OCM_VSCROLL(func) \
+ if (uMsg == OCM_VSCROLL) { \
+ SetMsgHandled(TRUE); \
+ func((int)LOWORD(wParam), (short)HIWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorEdit(CDCHandle dc, CEdit edit)
+#define MSG_OCM_CTLCOLOREDIT(func) \
+ if (uMsg == OCM_CTLCOLOREDIT) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorListBox(CDCHandle dc, CListBox listBox)
+#define MSG_OCM_CTLCOLORLISTBOX(func) \
+ if (uMsg == OCM_CTLCOLORLISTBOX) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorBtn(CDCHandle dc, CButton button)
+#define MSG_OCM_CTLCOLORBTN(func) \
+ if (uMsg == OCM_CTLCOLORBTN) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorDlg(CDCHandle dc, CWindow wnd)
+#define MSG_OCM_CTLCOLORDLG(func) \
+ if (uMsg == OCM_CTLCOLORDLG) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorScrollBar(CDCHandle dc, CScrollBar scrollBar)
+#define MSG_OCM_CTLCOLORSCROLLBAR(func) \
+ if (uMsg == OCM_CTLCOLORSCROLLBAR) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// HBRUSH OnReflectedCtlColorStatic(CDCHandle dc, CStatic wndStatic)
+#define MSG_OCM_CTLCOLORSTATIC(func) \
+ if (uMsg == OCM_CTLCOLORSTATIC) { \
+ SetMsgHandled(TRUE); \
+ lResult = (LRESULT)func((HDC)wParam, (HWND)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Edit specific messages
+
+// void OnClear()
+#define CR_MSG_WM_CLEAR(func) \
+ if (uMsg == WM_CLEAR) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCopy()
+#define CR_MSG_WM_COPY(func) \
+ if (uMsg == WM_COPY) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCut()
+#define CR_MSG_WM_CUT(func) \
+ if (uMsg == WM_CUT) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnPaste()
+#define CR_MSG_WM_PASTE(func) \
+ if (uMsg == WM_PASTE) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnUndo()
+#define CR_MSG_WM_UNDO(func) \
+ if (uMsg == WM_UNDO) { \
+ SetMsgHandled(TRUE); \
+ func(); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Generic message handlers
+
+// LRESULT OnMessageHandlerEX(UINT uMsg, WPARAM wParam, LPARAM lParam)
+#define CR_MESSAGE_HANDLER_EX(msg, func) \
+ if (uMsg == msg) { \
+ SetMsgHandled(TRUE); \
+ lResult = func(uMsg, wParam, lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnMessageRangeHandlerEX(UINT uMsg, WPARAM wParam, LPARAM lParam)
+#define CR_MESSAGE_RANGE_HANDLER_EX(msgFirst, msgLast, func) \
+ if (uMsg >= msgFirst && uMsg <= msgLast) { \
+ SetMsgHandled(TRUE); \
+ lResult = func(uMsg, wParam, lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+///////////////////////////////////////////////////////////////////////////////
+// Commands and notifications
+
+// void OnCommandHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define CR_COMMAND_HANDLER_EX(id, code, func) \
+ if (uMsg == WM_COMMAND && code == HIWORD(wParam) && id == LOWORD(wParam)) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define CR_COMMAND_ID_HANDLER_EX(id, func) \
+ if (uMsg == WM_COMMAND && id == LOWORD(wParam)) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCommandCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define CR_COMMAND_CODE_HANDLER_EX(code, func) \
+ if (uMsg == WM_COMMAND && code == HIWORD(wParam)) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotifyHandlerEX(LPNMHDR pnmh)
+#define CR_NOTIFY_HANDLER_EX(id, cd, func) \
+ if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && \
+ id == ((LPNMHDR)lParam)->idFrom) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotifyIDHandlerEX(LPNMHDR pnmh)
+#define CR_NOTIFY_ID_HANDLER_EX(id, func) \
+ if (uMsg == WM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotifyCodeHandlerEX(LPNMHDR pnmh)
+#define CR_NOTIFY_CODE_HANDLER_EX(cd, func) \
+ if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCommandRangeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define CR_COMMAND_RANGE_HANDLER_EX(idFirst, idLast, func) \
+ if (uMsg == WM_COMMAND && LOWORD(wParam) >= idFirst && \
+ LOWORD(wParam) <= idLast) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnCommandRangeCodeHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
+#define CR_COMMAND_RANGE_CODE_HANDLER_EX(idFirst, idLast, code, func) \
+ if (uMsg == WM_COMMAND && code == HIWORD(wParam) && \
+ LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotifyRangeHandlerEX(LPNMHDR pnmh)
+#define CR_NOTIFY_RANGE_HANDLER_EX(idFirst, idLast, func) \
+ if (uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && \
+ ((LPNMHDR)lParam)->idFrom <= idLast) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnNotifyRangeCodeHandlerEX(LPNMHDR pnmh)
+#define CR_NOTIFY_RANGE_CODE_HANDLER_EX(idFirst, idLast, cd, func) \
+ if (uMsg == WM_NOTIFY && cd == ((LPNMHDR)lParam)->code && \
+ ((LPNMHDR)lParam)->idFrom >= idFirst && \
+ ((LPNMHDR)lParam)->idFrom <= idLast) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedCommandHandlerEX(UINT uNotifyCode, int nID, CWindow
+// wndCtl)
+#define CR_REFLECTED_COMMAND_HANDLER_EX(id, code, func) \
+ if (uMsg == OCM_COMMAND && code == HIWORD(wParam) && id == LOWORD(wParam)) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow
+// wndCtl)
+#define CR_REFLECTED_COMMAND_ID_HANDLER_EX(id, func) \
+ if (uMsg == OCM_COMMAND && id == LOWORD(wParam)) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedCommandCodeHandlerEX(UINT uNotifyCode, int nID, CWindow
+// wndCtl)
+#define CR_REFLECTED_COMMAND_CODE_HANDLER_EX(code, func) \
+ if (uMsg == OCM_COMMAND && code == HIWORD(wParam)) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotifyHandlerEX(LPNMHDR pnmh)
+#define CR_REFLECTED_NOTIFY_HANDLER_EX(id, cd, func) \
+ if (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && \
+ id == ((LPNMHDR)lParam)->idFrom) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotifyIDHandlerEX(LPNMHDR pnmh)
+#define CR_REFLECTED_NOTIFY_ID_HANDLER_EX(id, func) \
+ if (uMsg == OCM_NOTIFY && id == ((LPNMHDR)lParam)->idFrom) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotifyCodeHandlerEX(LPNMHDR pnmh)
+#define CR_REFLECTED_NOTIFY_CODE_HANDLER_EX(cd, func) \
+ if (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedCommandRangeHandlerEX(UINT uNotifyCode, int nID, CWindow
+// wndCtl)
+#define CR_REFLECTED_COMMAND_RANGE_HANDLER_EX(idFirst, idLast, func) \
+ if (uMsg == OCM_COMMAND && LOWORD(wParam) >= idFirst && \
+ LOWORD(wParam) <= idLast) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// void OnReflectedCommandRangeCodeHandlerEX(UINT uNotifyCode, int nID, CWindow
+// wndCtl)
+#define CR_REFLECTED_COMMAND_RANGE_CODE_HANDLER_EX( \
+ idFirst, idLast, code, func) \
+ if (uMsg == OCM_COMMAND && code == HIWORD(wParam) && \
+ LOWORD(wParam) >= idFirst && LOWORD(wParam) <= idLast) { \
+ SetMsgHandled(TRUE); \
+ func((UINT)HIWORD(wParam), (int)LOWORD(wParam), (HWND)lParam); \
+ lResult = 0; \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotifyRangeHandlerEX(LPNMHDR pnmh)
+#define CR_REFLECTED_NOTIFY_RANGE_HANDLER_EX(idFirst, idLast, func) \
+ if (uMsg == OCM_NOTIFY && ((LPNMHDR)lParam)->idFrom >= idFirst && \
+ ((LPNMHDR)lParam)->idFrom <= idLast) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+// LRESULT OnReflectedNotifyRangeCodeHandlerEX(LPNMHDR pnmh)
+#define CR_REFLECTED_NOTIFY_RANGE_CODE_HANDLER_EX(idFirst, idLast, cd, func) \
+ if (uMsg == OCM_NOTIFY && cd == ((LPNMHDR)lParam)->code && \
+ ((LPNMHDR)lParam)->idFrom >= idFirst && \
+ ((LPNMHDR)lParam)->idFrom <= idLast) { \
+ SetMsgHandled(TRUE); \
+ lResult = func((LPNMHDR)lParam); \
+ if (IsMsgHandled()) \
+ return TRUE; \
+ }
+
+#define CR_DEFLATE_RECT(rect, by) \
+ { \
+ (rect)->left += (by)->left; \
+ (rect)->top += (by)->top; \
+ (rect)->right -= (by)->right; \
+ (rect)->bottom -= (by)->bottom; \
+ }
+
+#define CR_POINT_INITIALIZER_FROM_LPARAM(lparam) \
+ { LOWORD(lparam), HIWORD(lparam) }
+
+#endif // UI_GFX_WIN_MSG_UTIL_H_
diff --git a/chromium/ui/gfx/win/singleton_hwnd.cc b/chromium/ui/gfx/win/singleton_hwnd.cc
index 2de6a8b8a16..fc4d11f2d5e 100644
--- a/chromium/ui/gfx/win/singleton_hwnd.cc
+++ b/chromium/ui/gfx/win/singleton_hwnd.cc
@@ -37,8 +37,7 @@ BOOL SingletonHwnd::ProcessWindowMessage(HWND window,
}
SingletonHwnd::SingletonHwnd() {
- if (!base::MessageLoop::current() ||
- base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) {
+ if (!base::MessageLoopForUI::IsCurrent()) {
// Creating this window in (e.g.) a renderer inhibits shutdown on
// Windows. See http://crbug.com/230122 and http://crbug.com/236039.
DLOG(ERROR) << "Cannot create windows on non-UI thread!";
diff --git a/chromium/ui/gfx/win/window_impl.cc b/chromium/ui/gfx/win/window_impl.cc
index 7f0c232ae61..ff9fe57cf9d 100644
--- a/chromium/ui/gfx/win/window_impl.cc
+++ b/chromium/ui/gfx/win/window_impl.cc
@@ -97,7 +97,7 @@ ATOM ClassRegistrar::RetrieveClassAtom(const ClassInfo& class_info) {
}
// No class found, need to register one.
- string16 name = string16(WindowImpl::kBaseClassName) +
+ base::string16 name = base::string16(WindowImpl::kBaseClassName) +
base::IntToString16(registered_count_++);
WNDCLASSEX window_class;
@@ -226,10 +226,14 @@ HICON WindowImpl::GetDefaultWindowIcon() const {
LRESULT WindowImpl::OnWndProc(UINT message, WPARAM w_param, LPARAM l_param) {
LRESULT result = 0;
+ HWND hwnd = hwnd_;
+ if (message == WM_NCDESTROY)
+ hwnd_ = NULL;
+
// Handle the message if it's in our message map; otherwise, let the system
// handle it.
- if (!ProcessWindowMessage(hwnd_, message, w_param, l_param, result))
- result = DefWindowProc(hwnd_, message, w_param, l_param);
+ if (!ProcessWindowMessage(hwnd, message, w_param, l_param, result))
+ result = DefWindowProc(hwnd, message, w_param, l_param);
return result;
}
diff --git a/chromium/ui/gfx/win/window_impl.h b/chromium/ui/gfx/win/window_impl.h
index 1825c0b2f00..8206562935f 100644
--- a/chromium/ui/gfx/win/window_impl.h
+++ b/chromium/ui/gfx/win/window_impl.h
@@ -5,17 +5,13 @@
#ifndef UI_GFX_WIN_WINDOW_IMPL_H_
#define UI_GFX_WIN_WINDOW_IMPL_H_
-#include <atlbase.h>
-#include <atlapp.h>
-#include <atlmisc.h>
-#include <atlcrack.h>
-
#include <string>
#include "base/logging.h"
#include "ui/gfx/gfx_export.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect.h"
+#include "ui/gfx/win/msg_util.h"
namespace gfx {
diff --git a/chromium/ui/gfx/x/BUILD.gn b/chromium/ui/gfx/x/BUILD.gn
new file mode 100644
index 00000000000..d7ae7ed4ab9
--- /dev/null
+++ b/chromium/ui/gfx/x/BUILD.gn
@@ -0,0 +1,32 @@
+# 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.
+
+component("x") {
+ output_name = "gfx_x11"
+
+ sources = [
+ "x11_atom_cache.cc",
+ "x11_atom_cache.h",
+ "x11_connection.cc",
+ "x11_connection.h",
+ "x11_error_tracker.cc",
+ "x11_error_tracker.h",
+ "x11_switches.cc",
+ "x11_switches.h",
+ "x11_types.cc",
+ "x11_types.h",
+ ]
+
+ defines = [
+ "GFX_IMPLEMENTATION",
+ ]
+
+ configs += [
+ "//build/config/linux:x11",
+ ]
+
+ deps = [
+ "//base",
+ ]
+}
diff --git a/chromium/ui/gfx/x/gfx_x11.gyp b/chromium/ui/gfx/x/gfx_x11.gyp
new file mode 100644
index 00000000000..5be65ff1789
--- /dev/null
+++ b/chromium/ui/gfx/x/gfx_x11.gyp
@@ -0,0 +1,38 @@
+# 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.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ 'use_x11': 1, # It is necessary to explicitly set use_x11 here to make sure
+ # that the exclusion rules in filename_rules.gypi do not
+ # exclude the x11* files.
+ },
+
+ 'targets': [
+ {
+ 'target_name': 'gfx_x11',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../../../base/base.gyp:base',
+ '../../../build/linux/system.gyp:x11',
+ ],
+ 'defines': [
+ 'GFX_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'x11_atom_cache.cc',
+ 'x11_atom_cache.h',
+ 'x11_connection.cc',
+ 'x11_connection.h',
+ 'x11_error_tracker.cc',
+ 'x11_error_tracker.h',
+ 'x11_switches.cc',
+ 'x11_switches.h',
+ 'x11_types.cc',
+ 'x11_types.h',
+ ],
+ },
+ ]
+}
diff --git a/chromium/ui/gfx/x/x11_atom_cache.cc b/chromium/ui/gfx/x/x11_atom_cache.cc
index da75c0be34e..c9f52ca2aaa 100644
--- a/chromium/ui/gfx/x/x11_atom_cache.cc
+++ b/chromium/ui/gfx/x/x11_atom_cache.cc
@@ -5,20 +5,21 @@
#include "ui/gfx/x/x11_atom_cache.h"
#include <X11/Xatom.h>
+#include <X11/Xlib.h>
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
namespace ui {
-X11AtomCache::X11AtomCache(Display* xdisplay, const char** to_cache)
+X11AtomCache::X11AtomCache(XDisplay* xdisplay, const char** to_cache)
: xdisplay_(xdisplay),
uncached_atoms_allowed_(false) {
int cache_count = 0;
for (const char** i = to_cache; *i != NULL; i++)
cache_count++;
- scoped_ptr< ::Atom[]> cached_atoms(new ::Atom[cache_count]);
+ scoped_ptr<Atom[]> cached_atoms(new Atom[cache_count]);
// Grab all the atoms we need now to minimize roundtrips to the X11 server.
XInternAtoms(xdisplay_,
@@ -31,11 +32,11 @@ X11AtomCache::X11AtomCache(Display* xdisplay, const char** to_cache)
X11AtomCache::~X11AtomCache() {}
-::Atom X11AtomCache::GetAtom(const char* name) const {
- std::map<std::string, ::Atom>::const_iterator it = cached_atoms_.find(name);
+Atom X11AtomCache::GetAtom(const char* name) const {
+ std::map<std::string, Atom>::const_iterator it = cached_atoms_.find(name);
if (uncached_atoms_allowed_ && it == cached_atoms_.end()) {
- ::Atom atom = XInternAtom(xdisplay_, name, false);
+ Atom atom = XInternAtom(xdisplay_, name, false);
cached_atoms_.insert(std::make_pair(name, atom));
return atom;
}
diff --git a/chromium/ui/gfx/x/x11_atom_cache.h b/chromium/ui/gfx/x/x11_atom_cache.h
index fefa64205d0..6a29df720c6 100644
--- a/chromium/ui/gfx/x/x11_atom_cache.h
+++ b/chromium/ui/gfx/x/x11_atom_cache.h
@@ -5,16 +5,14 @@
#ifndef UI_GFX_X_X11_ATOM_CACHE_H_
#define UI_GFX_X_X11_ATOM_CACHE_H_
-#include "base/basictypes.h"
-#include "ui/gfx/gfx_export.h"
-
#include <map>
#include <string>
-#include <X11/Xlib.h>
+#include "base/basictypes.h"
+#include "ui/gfx/gfx_export.h"
-// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class.
-#undef RootWindow
+typedef unsigned long Atom;
+typedef struct _XDisplay XDisplay;
namespace ui {
@@ -25,22 +23,22 @@ namespace ui {
class GFX_EXPORT X11AtomCache {
public:
// Preinterns the NULL terminated list of string |to_cache_ on |xdisplay|.
- X11AtomCache(Display* xdisplay, const char** to_cache);
+ X11AtomCache(XDisplay* xdisplay, const char** to_cache);
~X11AtomCache();
// Returns the pre-interned Atom without having to go to the x server.
- ::Atom GetAtom(const char*) const;
+ Atom GetAtom(const char*) const;
// When an Atom isn't in the list of items we've cached, we should look it
// up, cache it locally, and then return the result.
void allow_uncached_atoms() { uncached_atoms_allowed_ = true; }
private:
- Display* xdisplay_;
+ XDisplay* xdisplay_;
bool uncached_atoms_allowed_;
- mutable std::map<std::string, ::Atom> cached_atoms_;
+ mutable std::map<std::string, Atom> cached_atoms_;
DISALLOW_COPY_AND_ASSIGN(X11AtomCache);
};
diff --git a/chromium/ui/gfx/x/x11_connection.cc b/chromium/ui/gfx/x/x11_connection.cc
new file mode 100644
index 00000000000..c5ee77f40d8
--- /dev/null
+++ b/chromium/ui/gfx/x/x11_connection.cc
@@ -0,0 +1,17 @@
+// 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_connection.h"
+
+#include <X11/Xlib.h>
+
+#include "ui/gfx/x/x11_types.h"
+
+namespace gfx {
+
+bool InitializeThreadedX11() {
+ return XInitThreads() && gfx::GetXDisplay();
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/x/x11_connection.h b/chromium/ui/gfx/x/x11_connection.h
new file mode 100644
index 00000000000..06ca89fe800
--- /dev/null
+++ b/chromium/ui/gfx/x/x11_connection.h
@@ -0,0 +1,18 @@
+// 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_CONNECTION_H_
+#define UI_GFX_X_X11_CONNECTION_H_
+
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// Initializes thread support for X11, and opens a connection to the display.
+// Return false if either fails, and true otherwise.
+GFX_EXPORT bool InitializeThreadedX11();
+
+} // namespace gfx
+
+#endif // UI_GFX_X_X11_CONNECTION_H_
diff --git a/chromium/ui/gfx/x/x11_error_tracker.cc b/chromium/ui/gfx/x/x11_error_tracker.cc
new file mode 100644
index 00000000000..110f79ccd02
--- /dev/null
+++ b/chromium/ui/gfx/x/x11_error_tracker.cc
@@ -0,0 +1,45 @@
+// 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 "base/logging.h"
+#include "ui/gfx/x/x11_error_tracker.h"
+
+#include "ui/gfx/x/x11_types.h"
+
+namespace {
+
+unsigned char g_x11_error_code = 0;
+static gfx::X11ErrorTracker* g_handler = NULL;
+
+int X11ErrorHandler(Display* display, XErrorEvent* error) {
+ g_x11_error_code = error->error_code;
+ return 0;
+}
+}
+
+namespace gfx {
+
+X11ErrorTracker::X11ErrorTracker() {
+ // This is a poor-man's check for incorrect usage. It disallows nested
+ // X11ErrorTracker instances on the same thread.
+ DCHECK(g_handler == NULL);
+ g_handler = this;
+ XSync(GetXDisplay(), False);
+ old_handler_ = XSetErrorHandler(X11ErrorHandler);
+ g_x11_error_code = 0;
+}
+
+X11ErrorTracker::~X11ErrorTracker() {
+ g_handler = NULL;
+ XSetErrorHandler(old_handler_);
+}
+
+bool X11ErrorTracker::FoundNewError() {
+ XSync(GetXDisplay(), False);
+ unsigned char error = g_x11_error_code;
+ g_x11_error_code = 0;
+ return error != 0;
+}
+
+} // namespace gfx
diff --git a/chromium/ui/gfx/x/x11_error_tracker.h b/chromium/ui/gfx/x/x11_error_tracker.h
new file mode 100644
index 00000000000..efcac0c7099
--- /dev/null
+++ b/chromium/ui/gfx/x/x11_error_tracker.h
@@ -0,0 +1,36 @@
+// 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_ERROR_TRACKER_H_
+#define UI_GFX_X_X11_ERROR_TRACKER_H_
+
+#include <X11/Xlib.h>
+
+#include "base/basictypes.h"
+#include "ui/gfx/gfx_export.h"
+
+namespace gfx {
+
+// X11ErrorTracker catches X11 errors in a non-fatal way. It does so by
+// temporarily changing the X11 error handler. The old error handler is
+// restored when the tracker is destroyed.
+class GFX_EXPORT X11ErrorTracker {
+ public:
+ X11ErrorTracker();
+ ~X11ErrorTracker();
+
+ // Returns whether an X11 error happened since this function was last called
+ // (or since the creation of the tracker). This is potentially expensive,
+ // since this causes a sync with the X server.
+ bool FoundNewError();
+
+ private:
+ XErrorHandler old_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(X11ErrorTracker);
+};
+
+} // namespace gfx
+
+#endif // UI_GFX_X_X11_ERROR_TRACKER_H_
diff --git a/chromium/ui/gfx/x/x11_switches.cc b/chromium/ui/gfx/x/x11_switches.cc
new file mode 100644
index 00000000000..bda0ad3c557
--- /dev/null
+++ b/chromium/ui/gfx/x/x11_switches.cc
@@ -0,0 +1,15 @@
+// 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 {
+
+#if !defined(OS_CHROMEOS)
+// Which X11 display to connect to. Emulates the GTK+ "--display=" command line
+// argument.
+const char kX11Display[] = "display";
+#endif
+
+} // namespace switches
diff --git a/chromium/ui/gfx/x/x11_switches.h b/chromium/ui/gfx/x/x11_switches.h
new file mode 100644
index 00000000000..4044c514154
--- /dev/null
+++ b/chromium/ui/gfx/x/x11_switches.h
@@ -0,0 +1,18 @@
+// 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 "ui/gfx/gfx_export.h"
+
+namespace switches {
+
+#if !defined(OS_CHROMEOS)
+GFX_EXPORT extern const char kX11Display[];
+#endif
+
+} // namespace switches
+
+#endif // UI_GFX_X_X11_SWITCHES_H_
diff --git a/chromium/ui/gfx/x/x11_types.cc b/chromium/ui/gfx/x/x11_types.cc
index 48ce6416b69..54a0816c652 100644
--- a/chromium/ui/gfx/x/x11_types.cc
+++ b/chromium/ui/gfx/x/x11_types.cc
@@ -6,12 +6,27 @@
#include <X11/Xlib.h>
+#include "base/command_line.h"
#include "base/message_loop/message_loop.h"
+#include "ui/gfx/x/x11_switches.h"
namespace gfx {
XDisplay* GetXDisplay() {
- return base::MessagePumpForUI::GetDefaultXDisplay();
+ static XDisplay* display = NULL;
+ if (!display)
+ display = OpenNewXDisplay();
+ return display;
+}
+
+XDisplay* OpenNewXDisplay() {
+#if defined(OS_CHROMEOS)
+ return XOpenDisplay(NULL);
+#else
+ std::string display_str = base::CommandLine::ForCurrentProcess()->
+ GetSwitchValueASCII(switches::kX11Display);
+ return XOpenDisplay(display_str.empty() ? NULL : display_str.c_str());
+#endif
}
void PutARGBImage(XDisplay* display,
diff --git a/chromium/ui/gfx/x/x11_types.h b/chromium/ui/gfx/x/x11_types.h
index 0f96fdc6a89..b9f1f9c1fce 100644
--- a/chromium/ui/gfx/x/x11_types.h
+++ b/chromium/ui/gfx/x/x11_types.h
@@ -20,6 +20,9 @@ namespace gfx {
// chrome codebase to get the display from window.
GFX_EXPORT XDisplay* GetXDisplay();
+// This opens a new X11 XDisplay*, taking command line arguments into account.
+GFX_EXPORT XDisplay* OpenNewXDisplay();
+
// Return the number of bits-per-pixel for a pixmap of the given depth
GFX_EXPORT int BitsPerPixelForPixmapDepth(XDisplay* display, int depth);