diff options
author | Andras Becsi <andras.becsi@digia.com> | 2014-03-18 13:16:26 +0100 |
---|---|---|
committer | Frederik Gladhorn <frederik.gladhorn@digia.com> | 2014-03-20 15:55:39 +0100 |
commit | 3f0f86b0caed75241fa71c95a5d73bc0164348c5 (patch) | |
tree | 92b9fb00f2e9e90b0be2262093876d4f43b6cd13 /chromium/ui/gfx | |
parent | e90d7c4b152c56919d963987e2503f9909a666d2 (diff) | |
download | qtwebengine-chromium-3f0f86b0caed75241fa71c95a5d73bc0164348c5.tar.gz |
Update to new stable branch 1750
This also includes an updated ninja and chromium dependencies
needed on Windows.
Change-Id: Icd597d80ed3fa4425933c9f1334c3c2e31291c42
Reviewed-by: Zoltan Arvai <zarvai@inf.u-szeged.hu>
Reviewed-by: Zeno Albisser <zeno.albisser@digia.com>
Diffstat (limited to 'chromium/ui/gfx')
217 files changed, 7244 insertions, 2071 deletions
diff --git a/chromium/ui/gfx/DEPS b/chromium/ui/gfx/DEPS index c2b61851728..07a2ea9406f 100644 --- a/chromium/ui/gfx/DEPS +++ b/chromium/ui/gfx/DEPS @@ -1,5 +1,8 @@ include_rules = [ "+base", - "+skia", + "+net", + "+skia/ext", "+third_party/angle", + "+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 fa08e88ba74..563c600ea4d 100644 --- a/chromium/ui/gfx/OWNERS +++ b/chromium/ui/gfx/OWNERS @@ -15,5 +15,9 @@ per-file display*=oshima@chromium.org per-file screen*=oshima@chromium.org # Transform, interpolated transform and transform util. +per-file transform*=shawnsingh@chromium.org per-file transform*=vollick@chromium.org per-file interpolated_transform*=vollick@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/DEPS b/chromium/ui/gfx/android/DEPS new file mode 100644 index 00000000000..c80012b5621 --- /dev/null +++ b/chromium/ui/gfx/android/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+jni", +] diff --git a/chromium/ui/gfx/android/device_display_info.cc b/chromium/ui/gfx/android/device_display_info.cc index 16fd2acb1d8..2de8440e1d3 100644 --- a/chromium/ui/gfx/android/device_display_info.cc +++ b/chromium/ui/gfx/android/device_display_info.cc @@ -4,63 +4,39 @@ #include "ui/gfx/android/device_display_info.h" -#include "base/android/jni_android.h" -#include "base/android/jni_string.h" #include "base/logging.h" -#include "jni/DeviceDisplayInfo_jni.h" - -using base::android::AttachCurrentThread; -using base::android::ScopedJavaLocalRef; +#include "ui/gfx/android/shared_device_display_info.h" namespace gfx { DeviceDisplayInfo::DeviceDisplayInfo() { - JNIEnv* env = AttachCurrentThread(); - j_device_info_.Reset(Java_DeviceDisplayInfo_create(env, - base::android::GetApplicationContext())); } DeviceDisplayInfo::~DeviceDisplayInfo() { } int DeviceDisplayInfo::GetDisplayHeight() { - JNIEnv* env = AttachCurrentThread(); - jint result = - Java_DeviceDisplayInfo_getDisplayHeight(env, j_device_info_.obj()); - return static_cast<int>(result); + return SharedDeviceDisplayInfo::GetInstance()->GetDisplayHeight(); } int DeviceDisplayInfo::GetDisplayWidth() { - JNIEnv* env = AttachCurrentThread(); - jint result = - Java_DeviceDisplayInfo_getDisplayWidth(env, j_device_info_.obj()); - return static_cast<int>(result); + return SharedDeviceDisplayInfo::GetInstance()->GetDisplayWidth(); } int DeviceDisplayInfo::GetBitsPerPixel() { - JNIEnv* env = AttachCurrentThread(); - jint result = - Java_DeviceDisplayInfo_getBitsPerPixel(env, j_device_info_.obj()); - return static_cast<int>(result); + return SharedDeviceDisplayInfo::GetInstance()->GetBitsPerPixel(); } int DeviceDisplayInfo::GetBitsPerComponent() { - JNIEnv* env = AttachCurrentThread(); - jint result = - Java_DeviceDisplayInfo_getBitsPerComponent(env, j_device_info_.obj()); - return static_cast<int>(result); + return SharedDeviceDisplayInfo::GetInstance()->GetBitsPerComponent(); } double DeviceDisplayInfo::GetDIPScale() { - JNIEnv* env = AttachCurrentThread(); - jdouble result = - Java_DeviceDisplayInfo_getDIPScale(env, j_device_info_.obj()); - return static_cast<double>(result); + return SharedDeviceDisplayInfo::GetInstance()->GetDIPScale(); } -// static -bool DeviceDisplayInfo::RegisterDeviceDisplayInfo(JNIEnv* env) { - return RegisterNativesImpl(env); +int DeviceDisplayInfo::GetSmallestDIPWidth() { + return SharedDeviceDisplayInfo::GetInstance()->GetSmallestDIPWidth(); } } // namespace gfx diff --git a/chromium/ui/gfx/android/device_display_info.h b/chromium/ui/gfx/android/device_display_info.h index 9f90f897b6a..83968e9b51e 100644 --- a/chromium/ui/gfx/android/device_display_info.h +++ b/chromium/ui/gfx/android/device_display_info.h @@ -8,7 +8,6 @@ #include <jni.h> #include <string> -#include "base/android/scoped_java_ref.h" #include "base/basictypes.h" #include "ui/gfx/gfx_export.h" @@ -16,7 +15,7 @@ namespace gfx { // Facilitates access to device information typically only // available using the Android SDK, including Display properties. -class UI_EXPORT DeviceDisplayInfo { +class GFX_EXPORT DeviceDisplayInfo { public: DeviceDisplayInfo(); ~DeviceDisplayInfo(); @@ -37,12 +36,10 @@ class UI_EXPORT DeviceDisplayInfo { // (1.0 is 160dpi, 0.75 is 120dpi, 2.0 is 320dpi). double GetDIPScale(); - // Registers methods with JNI and returns true if succeeded. - static bool RegisterDeviceDisplayInfo(JNIEnv* env); + // Smallest possible screen size in density-independent pixels. + int GetSmallestDIPWidth(); private: - base::android::ScopedJavaGlobalRef<jobject> j_device_info_; - DISALLOW_COPY_AND_ASSIGN(DeviceDisplayInfo); }; diff --git a/chromium/ui/gfx/android/java_bitmap.cc b/chromium/ui/gfx/android/java_bitmap.cc index 6c2eaa845a2..2a1be65d215 100644 --- a/chromium/ui/gfx/android/java_bitmap.cc +++ b/chromium/ui/gfx/android/java_bitmap.cc @@ -39,11 +39,11 @@ JavaBitmap::~JavaBitmap() { // static bool JavaBitmap::RegisterJavaBitmap(JNIEnv* env) { - return ui::RegisterNativesImpl(env); + return RegisterNativesImpl(env); } static ScopedJavaLocalRef<jobject> CreateJavaBitmap(const gfx::Size& size) { - return ui::Java_BitmapHelper_createBitmap(AttachCurrentThread(), + return Java_BitmapHelper_createBitmap(AttachCurrentThread(), size.width(), size.height()); } @@ -87,7 +87,7 @@ SkBitmap CreateSkBitmapFromResource(const char* name, gfx::Size size) { DCHECK(!size.IsEmpty()); JNIEnv* env = AttachCurrentThread(); ScopedJavaLocalRef<jstring> jname(env, env->NewStringUTF(name)); - ScopedJavaLocalRef<jobject> jobj(ui::Java_BitmapHelper_decodeDrawableResource( + ScopedJavaLocalRef<jobject> jobj(Java_BitmapHelper_decodeDrawableResource( env, jname.obj(), size.width(), size.height())); if (jobj.is_null()) return SkBitmap(); diff --git a/chromium/ui/gfx/android/java_bitmap.h b/chromium/ui/gfx/android/java_bitmap.h index 319ad79eb1e..9d1e4432cb7 100644 --- a/chromium/ui/gfx/android/java_bitmap.h +++ b/chromium/ui/gfx/android/java_bitmap.h @@ -17,7 +17,7 @@ namespace gfx { // 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. -class UI_EXPORT JavaBitmap { +class GFX_EXPORT JavaBitmap { public: explicit JavaBitmap(jobject bitmap); ~JavaBitmap(); @@ -41,14 +41,15 @@ class UI_EXPORT JavaBitmap { DISALLOW_COPY_AND_ASSIGN(JavaBitmap); }; -UI_EXPORT base::android::ScopedJavaLocalRef<jobject> ConvertToJavaBitmap( +GFX_EXPORT base::android::ScopedJavaLocalRef<jobject> ConvertToJavaBitmap( const SkBitmap* skbitmap); -UI_EXPORT SkBitmap CreateSkBitmapFromJavaBitmap(JavaBitmap& jbitmap); +GFX_EXPORT SkBitmap CreateSkBitmapFromJavaBitmap(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. -UI_EXPORT SkBitmap CreateSkBitmapFromResource(const char* name, gfx::Size size); +GFX_EXPORT SkBitmap CreateSkBitmapFromResource(const char* name, + gfx::Size size); } // namespace gfx diff --git a/chromium/ui/gfx/android/shared_device_display_info.cc b/chromium/ui/gfx/android/shared_device_display_info.cc new file mode 100644 index 00000000000..9ac18d0218d --- /dev/null +++ b/chromium/ui/gfx/android/shared_device_display_info.cc @@ -0,0 +1,128 @@ +// 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/android/shared_device_display_info.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "base/logging.h" +#include "jni/DeviceDisplayInfo_jni.h" + +namespace gfx { + +// static JNI call +static void UpdateSharedDeviceDisplayInfo(JNIEnv* env, + jobject obj, + jint display_height, + jint display_width, + jint bits_per_pixel, + jint bits_per_component, + jdouble dip_scale, + jint smallest_dip_width) { + SharedDeviceDisplayInfo::GetInstance()->InvokeUpdate(env, obj, + display_height, display_width, bits_per_pixel, bits_per_component, + dip_scale, smallest_dip_width); +} + +// static +SharedDeviceDisplayInfo* SharedDeviceDisplayInfo::GetInstance() { + return Singleton<SharedDeviceDisplayInfo>::get(); +} + +int SharedDeviceDisplayInfo::GetDisplayHeight() { + base::AutoLock autolock(lock_); + DCHECK_NE(0, display_height_); + return display_height_; +} + +int SharedDeviceDisplayInfo::GetDisplayWidth() { + base::AutoLock autolock(lock_); + DCHECK_NE(0, display_width_); + return display_width_; +} + +int SharedDeviceDisplayInfo::GetBitsPerPixel() { + base::AutoLock autolock(lock_); + DCHECK_NE(0, bits_per_pixel_); + return bits_per_pixel_; +} + +int SharedDeviceDisplayInfo::GetBitsPerComponent() { + base::AutoLock autolock(lock_); + DCHECK_NE(0, bits_per_component_); + return bits_per_component_; +} + +double SharedDeviceDisplayInfo::GetDIPScale() { + base::AutoLock autolock(lock_); + DCHECK_NE(0, dip_scale_); + return dip_scale_; +} + +int SharedDeviceDisplayInfo::GetSmallestDIPWidth() { + base::AutoLock autolock(lock_); + DCHECK_NE(0, smallest_dip_width_); + return smallest_dip_width_; +} + +// static +bool SharedDeviceDisplayInfo::RegisterSharedDeviceDisplayInfo(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +void SharedDeviceDisplayInfo::InvokeUpdate(JNIEnv* env, + jobject obj, + jint display_height, + jint display_width, + jint bits_per_pixel, + jint bits_per_component, + jdouble dip_scale, + jint smallest_dip_width) { + base::AutoLock autolock(lock_); + + UpdateDisplayInfo(env, obj, display_height, + display_width, bits_per_pixel, bits_per_component, dip_scale, + smallest_dip_width); +} + +SharedDeviceDisplayInfo::SharedDeviceDisplayInfo() + : display_height_(0), + display_width_(0), + bits_per_pixel_(0), + bits_per_component_(0), + dip_scale_(0), + smallest_dip_width_(0) { + JNIEnv* env = base::android::AttachCurrentThread(); + j_device_info_.Reset( + Java_DeviceDisplayInfo_createWithListener(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_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())); +} + +SharedDeviceDisplayInfo::~SharedDeviceDisplayInfo() { +} + +void SharedDeviceDisplayInfo::UpdateDisplayInfo(JNIEnv* env, + jobject jobj, + jint display_height, + jint display_width, + jint bits_per_pixel, + jint bits_per_component, + jdouble dip_scale, + jint smallest_dip_width) { + display_height_ = static_cast<int>(display_height); + display_width_ = static_cast<int>(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); +} + +} // namespace gfx diff --git a/chromium/ui/gfx/android/shared_device_display_info.h b/chromium/ui/gfx/android/shared_device_display_info.h new file mode 100644 index 00000000000..1e1fc0c6662 --- /dev/null +++ b/chromium/ui/gfx/android/shared_device_display_info.h @@ -0,0 +1,68 @@ +// 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_ANDROID_SHARED_DEVICE_DISPLAY_INFO_H_ +#define UI_GFX_ANDROID_SHARED_DEVICE_DISPLAY_INFO_H_ + +#include "base/android/scoped_java_ref.h" +#include "base/basictypes.h" +#include "base/memory/singleton.h" +#include "base/synchronization/lock.h" + +namespace gfx { + +// Facilitates access to device information typically only +// available using the Android SDK, including Display properties. +class SharedDeviceDisplayInfo { + public: + static SharedDeviceDisplayInfo* GetInstance(); + + int GetDisplayHeight(); + int GetDisplayWidth(); + int GetBitsPerPixel(); + int GetBitsPerComponent(); + double GetDIPScale(); + int GetSmallestDIPWidth(); + + // Registers methods with JNI and returns true if succeeded. + static bool RegisterSharedDeviceDisplayInfo(JNIEnv* env); + + void InvokeUpdate(JNIEnv* env, + jobject jobj, + jint display_height, + jint display_width, + jint bits_per_pixel, + jint bits_per_component, + jdouble dip_scale, + jint smallest_dip_width); + private: + friend struct DefaultSingletonTraits<SharedDeviceDisplayInfo>; + + SharedDeviceDisplayInfo(); + ~SharedDeviceDisplayInfo(); + void UpdateDisplayInfo(JNIEnv* env, + jobject jobj, + jint display_height, + jint display_width, + jint bits_per_pixel, + jint bits_per_component, + jdouble dip_scale, + jint smallest_dip_width); + + base::Lock lock_; + base::android::ScopedJavaGlobalRef<jobject> j_device_info_; + + int display_height_; + int display_width_; + int bits_per_pixel_; + int bits_per_component_; + double dip_scale_; + int smallest_dip_width_; + + DISALLOW_COPY_AND_ASSIGN(SharedDeviceDisplayInfo); +}; + +} // namespace gfx + +#endif // UI_GFX_ANDROID_SHARED_DEVICE_DISPLAY_INFO_H_ diff --git a/chromium/ui/gfx/android/view_configuration.cc b/chromium/ui/gfx/android/view_configuration.cc new file mode 100644 index 00000000000..63657178b15 --- /dev/null +++ b/chromium/ui/gfx/android/view_configuration.cc @@ -0,0 +1,56 @@ +// 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/android/view_configuration.h" + +#include "base/android/jni_android.h" +#include "jni/ViewConfiguration_jni.h" + +using namespace JNI_ViewConfiguration; +using base::android::AttachCurrentThread; +using base::android::GetApplicationContext; + +namespace gfx { + +int ViewConfiguration::GetDoubleTapTimeoutInMs() { + JNIEnv* env = AttachCurrentThread(); + return Java_ViewConfiguration_getDoubleTapTimeout(env); +} + +int ViewConfiguration::GetLongPressTimeoutInMs() { + JNIEnv* env = AttachCurrentThread(); + return Java_ViewConfiguration_getLongPressTimeout(env); +} + +int ViewConfiguration::GetTapTimeoutInMs() { + JNIEnv* env = AttachCurrentThread(); + return Java_ViewConfiguration_getTapTimeout(env); +} + +int ViewConfiguration::GetMaximumFlingVelocityInPixelsPerSecond() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> view = + Java_ViewConfiguration_get(env, GetApplicationContext()); + return Java_ViewConfiguration_getScaledMaximumFlingVelocity(env, view.obj()); +} + +int ViewConfiguration::GetMinimumFlingVelocityInPixelsPerSecond() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> view = + Java_ViewConfiguration_get(env, GetApplicationContext()); + return Java_ViewConfiguration_getScaledMinimumFlingVelocity(env, view.obj()); +} + +int ViewConfiguration::GetTouchSlopInPixels() { + JNIEnv* env = AttachCurrentThread(); + ScopedJavaLocalRef<jobject> view = + Java_ViewConfiguration_get(env, GetApplicationContext()); + return Java_ViewConfiguration_getScaledTouchSlop(env, view.obj()); +} + +bool ViewConfiguration::RegisterViewConfiguration(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +} // namespace gfx diff --git a/chromium/ui/gfx/android/view_configuration.h b/chromium/ui/gfx/android/view_configuration.h new file mode 100644 index 00000000000..f0995cb3e29 --- /dev/null +++ b/chromium/ui/gfx/android/view_configuration.h @@ -0,0 +1,32 @@ +// 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_ANDROID_VIEW_CONFIGURATION_H_ +#define UI_GFX_ANDROID_VIEW_CONFIGURATION_H_ + +#include <jni.h> + +#include "ui/gfx/gfx_export.h" + +namespace gfx { + +// Provides access to Android's ViewConfiguration for gesture-related constants. +class GFX_EXPORT ViewConfiguration { + public: + static int GetDoubleTapTimeoutInMs(); + static int GetLongPressTimeoutInMs(); + static int GetTapTimeoutInMs(); + + static int GetMaximumFlingVelocityInPixelsPerSecond(); + static int GetMinimumFlingVelocityInPixelsPerSecond(); + + static int GetTouchSlopInPixels(); + + // Registers methods with JNI and returns true if succeeded. + static bool RegisterViewConfiguration(JNIEnv* env); +}; + +} // namespace gfx + +#endif // UI_GFX_ANDROID_VIEW_CONFIGURATION_H_ diff --git a/chromium/ui/gfx/animation/animation.cc b/chromium/ui/gfx/animation/animation.cc index ba0bac822cc..3b525f22f00 100644 --- a/chromium/ui/gfx/animation/animation.cc +++ b/chromium/ui/gfx/animation/animation.cc @@ -62,16 +62,17 @@ void Animation::Stop() { } double Animation::CurrentValueBetween(double start, double target) const { - return Tween::ValueBetween(GetCurrentValue(), start, target); + return Tween::DoubleValueBetween(GetCurrentValue(), start, target); } int Animation::CurrentValueBetween(int start, int target) const { - return Tween::ValueBetween(GetCurrentValue(), start, target); + return Tween::IntValueBetween(GetCurrentValue(), start, target); } gfx::Rect Animation::CurrentValueBetween(const gfx::Rect& start_bounds, const gfx::Rect& target_bounds) const { - return Tween::ValueBetween(GetCurrentValue(), start_bounds, target_bounds); + return Tween::RectValueBetween( + GetCurrentValue(), start_bounds, target_bounds); } void Animation::SetContainer(AnimationContainer* container) { diff --git a/chromium/ui/gfx/animation/animation_container.cc b/chromium/ui/gfx/animation/animation_container.cc index c76f1bb7797..d8290b2eef6 100644 --- a/chromium/ui/gfx/animation/animation_container.cc +++ b/chromium/ui/gfx/animation/animation_container.cc @@ -6,6 +6,7 @@ #include "ui/gfx/animation/animation_container_element.h" #include "ui/gfx/animation/animation_container_observer.h" +#include "ui/gfx/frame_time.h" using base::TimeDelta; using base::TimeTicks; @@ -13,7 +14,7 @@ using base::TimeTicks; namespace gfx { AnimationContainer::AnimationContainer() - : last_tick_time_(TimeTicks::Now()), + : last_tick_time_(gfx::FrameTime::Now()), observer_(NULL) { } @@ -28,7 +29,7 @@ void AnimationContainer::Start(AnimationContainerElement* element) { // element isn't running. if (elements_.empty()) { - last_tick_time_ = TimeTicks::Now(); + last_tick_time_ = gfx::FrameTime::Now(); SetMinTimerInterval(element->GetTimerInterval()); } else if (element->GetTimerInterval() < min_timer_interval_) { SetMinTimerInterval(element->GetTimerInterval()); @@ -61,7 +62,7 @@ void AnimationContainer::Run() { // ourself here to make sure we're still valid after running all the elements. scoped_refptr<AnimationContainer> this_ref(this); - TimeTicks current_time = TimeTicks::Now(); + TimeTicks current_time = gfx::FrameTime::Now(); last_tick_time_ = current_time; diff --git a/chromium/ui/gfx/animation/animation_container_unittest.cc b/chromium/ui/gfx/animation/animation_container_unittest.cc index 25977c26161..70d3b0e10f8 100644 --- a/chromium/ui/gfx/animation/animation_container_unittest.cc +++ b/chromium/ui/gfx/animation/animation_container_unittest.cc @@ -5,27 +5,40 @@ #include "ui/gfx/animation/animation_container.h" #include "base/memory/scoped_ptr.h" -#include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/animation/animation_container_observer.h" #include "ui/gfx/animation/linear_animation.h" #include "ui/gfx/animation/test_animation_delegate.h" -using testing::AtLeast; - namespace gfx { namespace { -class MockObserver : public AnimationContainerObserver { +class FakeAnimationContainerObserver : public AnimationContainerObserver { public: - MockObserver() {} + FakeAnimationContainerObserver() + : progressed_count_(0), + empty_(false) { + } - MOCK_METHOD1(AnimationContainerProgressed, void(AnimationContainer*)); - MOCK_METHOD1(AnimationContainerEmpty, void(AnimationContainer*)); + int progressed_count() const { return progressed_count_; } + bool empty() const { return empty_; } private: - DISALLOW_COPY_AND_ASSIGN(MockObserver); + virtual void AnimationContainerProgressed( + AnimationContainer* container) OVERRIDE { + progressed_count_++; + } + + // Invoked when no more animations are being managed by this container. + virtual void AnimationContainerEmpty(AnimationContainer* container) OVERRIDE { + empty_ = true; + } + + int progressed_count_; + bool empty_; + + DISALLOW_COPY_AND_ASSIGN(FakeAnimationContainerObserver); }; class TestAnimation : public LinearAnimation { @@ -94,7 +107,7 @@ TEST_F(AnimationContainerTest, Multi) { // Makes sure observer is notified appropriately. TEST_F(AnimationContainerTest, Observer) { - MockObserver observer; + FakeAnimationContainerObserver observer; TestAnimationDelegate delegate1; scoped_refptr<AnimationContainer> container(new AnimationContainer()); @@ -102,12 +115,6 @@ TEST_F(AnimationContainerTest, Observer) { TestAnimation animation1(&delegate1); animation1.SetContainer(container.get()); - // We expect to get these two calls: the animation progressed, and then when - // the animation completed the container went empty. - EXPECT_CALL(observer, AnimationContainerProgressed(container.get())).Times( - AtLeast(1)); - EXPECT_CALL(observer, AnimationContainerEmpty(container.get())).Times(1); - // Start the animation. animation1.Start(); EXPECT_TRUE(container->is_running()); @@ -115,9 +122,13 @@ TEST_F(AnimationContainerTest, Observer) { // Run the message loop. The delegate quits the message loop when notified. base::MessageLoop::current()->Run(); + EXPECT_EQ(1, observer.progressed_count()); + // The timer should have finished. EXPECT_TRUE(delegate1.finished()); + EXPECT_TRUE(observer.empty()); + // And the container should no longer be running. EXPECT_FALSE(container->is_running()); diff --git a/chromium/ui/gfx/animation/tween.cc b/chromium/ui/gfx/animation/tween.cc index 4d1a6b3b260..174305078c2 100644 --- a/chromium/ui/gfx/animation/tween.cc +++ b/chromium/ui/gfx/animation/tween.cc @@ -10,7 +10,11 @@ #include <float.h> #endif +#include <algorithm> + +#include "base/basictypes.h" #include "base/logging.h" +#include "ui/gfx/safe_integer_conversions.h" namespace gfx { @@ -55,13 +59,70 @@ double Tween::CalculateValue(Tween::Type type, double state) { return state; } +namespace { +uint8 FloatToColorByte(float f) { + return std::min(std::max(ToRoundedInt(f * 255.f), 0), 255); +} + +uint8 BlendColorComponents(uint8 start, + uint8 target, + float start_alpha, + float target_alpha, + float blended_alpha, + double progress) { + // Since progress can be outside [0, 1], blending can produce a value outside + // [0, 255]. + float blended_premultiplied = Tween::FloatValueBetween( + progress, start / 255.f * start_alpha, target / 255.f * target_alpha); + return FloatToColorByte(blended_premultiplied / blended_alpha); +} + +} // namespace + +// static +SkColor Tween::ColorValueBetween(double value, SkColor start, SkColor target) { + float start_a = SkColorGetA(start) / 255.f; + float target_a = SkColorGetA(target) / 255.f; + float blended_a = FloatValueBetween(value, start_a, target_a); + if (blended_a <= 0.f) + return SkColorSetARGB(0, 0, 0, 0); + blended_a = std::min(blended_a, 1.f); + + uint8 blended_r = BlendColorComponents(SkColorGetR(start), + SkColorGetR(target), + start_a, + target_a, + blended_a, + value); + uint8 blended_g = BlendColorComponents(SkColorGetG(start), + SkColorGetG(target), + start_a, + target_a, + blended_a, + value); + uint8 blended_b = BlendColorComponents(SkColorGetB(start), + SkColorGetB(target), + start_a, + target_a, + blended_a, + value); + + return SkColorSetARGB( + FloatToColorByte(blended_a), blended_r, blended_g, blended_b); +} + // static -double Tween::ValueBetween(double value, double start, double target) { +double Tween::DoubleValueBetween(double value, double start, double target) { return start + (target - start) * value; } // static -int Tween::ValueBetween(double value, int start, int target) { +float Tween::FloatValueBetween(double value, float start, float target) { + return static_cast<float>(start + (target - start) * value); +} + +// static +int Tween::IntValueBetween(double value, int start, int target) { if (start == target) return start; double delta = static_cast<double>(target - start); @@ -76,22 +137,28 @@ int Tween::ValueBetween(double value, int start, int target) { #endif } +//static +int Tween::LinearIntValueBetween(double value, int start, int target) { + return std::floor(0.5 + DoubleValueBetween(value, start, target)); +} + // static -gfx::Rect Tween::ValueBetween(double value, - const gfx::Rect& start_bounds, - const gfx::Rect& target_bounds) { - return gfx::Rect(ValueBetween(value, start_bounds.x(), target_bounds.x()), - ValueBetween(value, start_bounds.y(), target_bounds.y()), - ValueBetween(value, start_bounds.width(), - target_bounds.width()), - ValueBetween(value, start_bounds.height(), - target_bounds.height())); +gfx::Rect Tween::RectValueBetween(double value, + const gfx::Rect& start_bounds, + const gfx::Rect& target_bounds) { + return gfx::Rect( + LinearIntValueBetween(value, start_bounds.x(), target_bounds.x()), + LinearIntValueBetween(value, start_bounds.y(), target_bounds.y()), + LinearIntValueBetween(value, start_bounds.width(), target_bounds.width()), + LinearIntValueBetween( + value, start_bounds.height(), target_bounds.height())); } // static -gfx::Transform Tween::ValueBetween(double value, - const gfx::Transform& start_transform, - const gfx::Transform& end_transform) { +gfx::Transform Tween::TransformValueBetween( + double value, + const gfx::Transform& start_transform, + const gfx::Transform& end_transform) { if (value >= 1.0) return end_transform; if (value <= 0.0) diff --git a/chromium/ui/gfx/animation/tween.h b/chromium/ui/gfx/animation/tween.h index 0c1f7585ecf..04f353db1ae 100644 --- a/chromium/ui/gfx/animation/tween.h +++ b/chromium/ui/gfx/animation/tween.h @@ -6,6 +6,7 @@ #define UI_GFX_ANIMATION_TWEEN_H_ #include "base/basictypes.h" +#include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/gfx_export.h" #include "ui/gfx/rect.h" #include "ui/gfx/transform.h" @@ -30,14 +31,27 @@ class GFX_EXPORT Tween { static double CalculateValue(Type type, double state); // Conveniences for getting a value between a start and end point. - static double ValueBetween(double value, double start, double target); - static int ValueBetween(double value, int start, int target); - static gfx::Rect ValueBetween(double value, - const gfx::Rect& start_bounds, - const gfx::Rect& target_bounds); - static gfx::Transform ValueBetween(double value, - const gfx::Transform& start_transform, - const gfx::Transform& target_transform); + static SkColor ColorValueBetween(double value, SkColor start, SkColor target); + static double DoubleValueBetween(double value, double start, double target); + static float FloatValueBetween(double value, float start, float target); + + // Interpolated between start and target, with every integer in this range + // given equal weight. + static int IntValueBetween(double value, int start, int target); + + // Interpolates between start and target as real numbers, and rounds the + // result to the nearest integer, with ties broken by rounding towards + // positive infinity. This gives start and target half the weight of the + // other integers in the range. This is the integer interpolation approach + // specified by www.w3.org/TR/css3-transitions. + static int LinearIntValueBetween(double value, int start, int target); + static gfx::Rect RectValueBetween(double value, + const gfx::Rect& start_bounds, + const gfx::Rect& target_bounds); + static gfx::Transform TransformValueBetween( + double value, + const gfx::Transform& start_transform, + const gfx::Transform& target_transform); private: Tween(); diff --git a/chromium/ui/gfx/animation/tween_unittest.cc b/chromium/ui/gfx/animation/tween_unittest.cc new file mode 100644 index 00000000000..d92fe1bacc4 --- /dev/null +++ b/chromium/ui/gfx/animation/tween_unittest.cc @@ -0,0 +1,136 @@ +// 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/animation/tween.h" + +#include <math.h> + +#if defined(OS_WIN) +#include <float.h> +#endif + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/test/color_util.h" + +namespace gfx { +namespace { + +double next_double(double d) { +#if defined(OS_WIN) + return _nextafter(d, d+1); +#else + return nextafter(d, d+1); +#endif +} + +// Validates that the same interpolations are made as in Blink. +TEST(TweenTest, ColorValueBetween) { + // From blink's AnimatableColorTest. + EXPECT_SKCOLOR_EQ(0xFF00FF00, + Tween::ColorValueBetween(-10.0, 0xFF00FF00, 0xFF00FF00)); + EXPECT_SKCOLOR_EQ(0xFF00FF00, + Tween::ColorValueBetween(-10.0, 0xFF00FF00, 0xFFFF00FF)); + EXPECT_SKCOLOR_EQ(0xFF00FF00, + Tween::ColorValueBetween(0.0, 0xFF00FF00, 0xFFFF00FF)); + EXPECT_SKCOLOR_EQ(0xFF01FE01, + Tween::ColorValueBetween(1.0 / 255, 0xFF00FF00, 0xFFFF00FF)); + EXPECT_SKCOLOR_EQ(0xFF808080, + Tween::ColorValueBetween(0.5, 0xFF00FF00, 0xFFFF00FF)); + EXPECT_SKCOLOR_EQ( + 0xFFFE01FE, + Tween::ColorValueBetween(254.0 / 255.0, 0xFF00FF00, 0xFFFF00FF)); + EXPECT_SKCOLOR_EQ(0xFFFF00FF, + Tween::ColorValueBetween(1.0, 0xFF00FF00, 0xFFFF00FF)); + EXPECT_SKCOLOR_EQ(0xFFFF00FF, + Tween::ColorValueBetween(10.0, 0xFF00FF00, 0xFFFF00FF)); + EXPECT_SKCOLOR_EQ(0xFF0C253E, + Tween::ColorValueBetween(3.0 / 16.0, 0xFF001020, 0xFF4080C0)); + EXPECT_SKCOLOR_EQ(0x80FF00FF, + Tween::ColorValueBetween(0.5, 0x0000FF00, 0xFFFF00FF)); + EXPECT_SKCOLOR_EQ(0x60AA55AA, + Tween::ColorValueBetween(0.5, 0x4000FF00, 0x80FF00FF)); + EXPECT_SKCOLOR_EQ(0x60FFAAFF, + Tween::ColorValueBetween(0.5, 0x40FF00FF, 0x80FFFFFF)); + EXPECT_SKCOLOR_EQ(0x103060A0, + Tween::ColorValueBetween(0.5, 0x10204080, 0x104080C0)); +} + +// Ensures that each of the 3 integers in [0, 1, 2] ae selected with equal +// weight. +TEST(TweenTest, IntValueBetween) { + EXPECT_EQ(0, Tween::IntValueBetween(0.0, 0, 2)); + EXPECT_EQ(0, Tween::IntValueBetween(0.5 / 3.0, 0, 2)); + EXPECT_EQ(0, Tween::IntValueBetween(1.0 / 3.0, 0, 2)); + + EXPECT_EQ(1, Tween::IntValueBetween(next_double(1.0 / 3.0), 0, 2)); + EXPECT_EQ(1, Tween::IntValueBetween(1.5 / 3.0, 0, 2)); + EXPECT_EQ(1, Tween::IntValueBetween(2.0 / 3.0, 0, 2)); + + EXPECT_EQ(2, Tween::IntValueBetween(next_double(2.0 / 3.0), 0, 2)); + EXPECT_EQ(2, Tween::IntValueBetween(2.5 / 3.0, 0, 2)); + EXPECT_EQ(2, Tween::IntValueBetween(3.0 / 3.0, 0, 2)); +} + +TEST(TweenTest, IntValueBetweenNegative) { + EXPECT_EQ(-2, Tween::IntValueBetween(0.0, -2, 0)); + EXPECT_EQ(-2, Tween::IntValueBetween(0.5 / 3.0, -2, 0)); + EXPECT_EQ(-2, Tween::IntValueBetween(1.0 / 3.0, -2, 0)); + + EXPECT_EQ(-1, Tween::IntValueBetween(next_double(1.0 / 3.0), -2, 0)); + EXPECT_EQ(-1, Tween::IntValueBetween(1.5 / 3.0, -2, 0)); + EXPECT_EQ(-1, Tween::IntValueBetween(2.0 / 3.0, -2, 0)); + + EXPECT_EQ(0, Tween::IntValueBetween(next_double(2.0 / 3.0), -2, 0)); + EXPECT_EQ(0, Tween::IntValueBetween(2.5 / 3.0, -2, 0)); + EXPECT_EQ(0, Tween::IntValueBetween(3.0 / 3.0, -2, 0)); +} + +TEST(TweenTest, IntValueBetweenReverse) { + EXPECT_EQ(2, Tween::IntValueBetween(0.0, 2, 0)); + EXPECT_EQ(2, Tween::IntValueBetween(0.5 / 3.0, 2, 0)); + EXPECT_EQ(2, Tween::IntValueBetween(1.0 / 3.0, 2, 0)); + + EXPECT_EQ(1, Tween::IntValueBetween(next_double(1.0 / 3.0), 2, 0)); + EXPECT_EQ(1, Tween::IntValueBetween(1.5 / 3.0, 2, 0)); + EXPECT_EQ(1, Tween::IntValueBetween(2.0 / 3.0, 2, 0)); + + EXPECT_EQ(0, Tween::IntValueBetween(next_double(2.0 / 3.0), 2, 0)); + EXPECT_EQ(0, Tween::IntValueBetween(2.5 / 3.0, 2, 0)); + EXPECT_EQ(0, Tween::IntValueBetween(3.0 / 3.0, 2, 0)); +} + +TEST(TweenTest, LinearIntValueBetween) { + EXPECT_EQ(0, Tween::LinearIntValueBetween(0.0, 0, 2)); + EXPECT_EQ(0, Tween::LinearIntValueBetween(0.5 / 4.0, 0, 2)); + EXPECT_EQ(0, Tween::LinearIntValueBetween(0.99 / 4.0, 0, 2)); + + EXPECT_EQ(1, Tween::LinearIntValueBetween(1.0 / 4.0, 0, 2)); + EXPECT_EQ(1, Tween::LinearIntValueBetween(1.5 / 4.0, 0, 2)); + EXPECT_EQ(1, Tween::LinearIntValueBetween(2.0 / 4.0, 0, 2)); + EXPECT_EQ(1, Tween::LinearIntValueBetween(2.5 / 4.0, 0, 2)); + EXPECT_EQ(1, Tween::LinearIntValueBetween(2.99 / 4.0, 0, 2)); + + EXPECT_EQ(2, Tween::LinearIntValueBetween(3.0 / 4.0, 0, 2)); + EXPECT_EQ(2, Tween::LinearIntValueBetween(3.5 / 4.0, 0, 2)); + EXPECT_EQ(2, Tween::LinearIntValueBetween(4.0 / 4.0, 0, 2)); +} + +TEST(TweenTest, LinearIntValueBetweenNegative) { + EXPECT_EQ(-2, Tween::LinearIntValueBetween(0.0, -2, 0)); + EXPECT_EQ(-2, Tween::LinearIntValueBetween(0.5 / 4.0, -2, 0)); + EXPECT_EQ(-2, Tween::LinearIntValueBetween(0.99 / 4.0, -2, 0)); + + EXPECT_EQ(-1, Tween::LinearIntValueBetween(1.0 / 4.0, -2, 0)); + EXPECT_EQ(-1, Tween::LinearIntValueBetween(1.5 / 4.0, -2, 0)); + EXPECT_EQ(-1, Tween::LinearIntValueBetween(2.0 / 4.0, -2, 0)); + EXPECT_EQ(-1, Tween::LinearIntValueBetween(2.5 / 4.0, -2, 0)); + EXPECT_EQ(-1, Tween::LinearIntValueBetween(2.99 / 4.0, -2, 0)); + + EXPECT_EQ(0, Tween::LinearIntValueBetween(3.0 / 4.0, -2, 0)); + EXPECT_EQ(0, Tween::LinearIntValueBetween(3.5 / 4.0, -2, 0)); + EXPECT_EQ(0, Tween::LinearIntValueBetween(4.0 / 4.0, -2, 0)); +} + +} // namespace +} // namespace gfx diff --git a/chromium/ui/gfx/blit.cc b/chromium/ui/gfx/blit.cc index a0bae8a17ed..4b87bc9aac5 100644 --- a/chromium/ui/gfx/blit.cc +++ b/chromium/ui/gfx/blit.cc @@ -11,11 +11,13 @@ #include "ui/gfx/rect.h" #include "ui/gfx/vector2d.h" +#if defined(USE_CAIRO) #if defined(OS_OPENBSD) #include <cairo.h> #elif defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) #include <cairo/cairo.h> #endif +#endif #if defined(OS_MACOSX) #include "base/mac/scoped_cftyperef.h" @@ -76,9 +78,7 @@ void BlitContextToContext(NativeDrawingContext dst_context, base::ScopedCFTypeRef<CGImageRef> src_sub_image( CGImageCreateWithImageInRect(src_image, src_rect.ToCGRect())); CGContextDrawImage(dst_context, dst_rect.ToCGRect(), src_sub_image); -#elif defined(OS_ANDROID) - NOTIMPLEMENTED(); -#else // Linux, BSD, others +#elif defined(USE_CAIRO) // Only translations in the source context are supported; more complex // source context transforms will be ignored. cairo_save(dst_context); @@ -92,6 +92,8 @@ void BlitContextToContext(NativeDrawingContext dst_context, cairo_clip(dst_context); cairo_paint(dst_context); cairo_restore(dst_context); +#else + NOTIMPLEMENTED(); #endif } diff --git a/chromium/ui/gfx/blit.h b/chromium/ui/gfx/blit.h index f0668172c05..af56636bce7 100644 --- a/chromium/ui/gfx/blit.h +++ b/chromium/ui/gfx/blit.h @@ -17,35 +17,35 @@ class Rect; class Vector2d; // Blits a rectangle from the source context into the destination context. -UI_EXPORT void BlitContextToContext(NativeDrawingContext dst_context, +GFX_EXPORT void BlitContextToContext(NativeDrawingContext dst_context, + const Rect& dst_rect, + NativeDrawingContext src_context, + const Point& src_origin); + +// Blits a rectangle from the source context into the destination canvas. +GFX_EXPORT void BlitContextToCanvas(SkCanvas *dst_canvas, const Rect& dst_rect, NativeDrawingContext src_context, const Point& src_origin); -// Blits a rectangle from the source context into the destination canvas. -UI_EXPORT void BlitContextToCanvas(SkCanvas *dst_canvas, - const Rect& dst_rect, - NativeDrawingContext src_context, - const Point& src_origin); - // Blits a rectangle from the source canvas into the destination context. -UI_EXPORT void BlitCanvasToContext(NativeDrawingContext dst_context, +GFX_EXPORT void BlitCanvasToContext(NativeDrawingContext dst_context, + const Rect& dst_rect, + SkCanvas *src_canvas, + const Point& src_origin); + +// Blits a rectangle from the source canvas into the destination canvas. +GFX_EXPORT void BlitCanvasToCanvas(SkCanvas *dst_canvas, const Rect& dst_rect, SkCanvas *src_canvas, const Point& src_origin); -// Blits a rectangle from the source canvas into the destination canvas. -UI_EXPORT void BlitCanvasToCanvas(SkCanvas *dst_canvas, - const Rect& dst_rect, - SkCanvas *src_canvas, - const Point& src_origin); - // Scrolls the given subset of the given canvas by the given offset. // The canvas should not have a clip or a transform applied, since platforms // may implement those operations differently. -UI_EXPORT void ScrollCanvas(SkCanvas* canvas, - const Rect& clip, - const Vector2d& offset); +GFX_EXPORT void ScrollCanvas(SkCanvas* canvas, + const Rect& clip, + const Vector2d& offset); } // namespace gfx diff --git a/chromium/ui/gfx/box_f.cc b/chromium/ui/gfx/box_f.cc index efb57967145..62e755bdc3e 100644 --- a/chromium/ui/gfx/box_f.cc +++ b/chromium/ui/gfx/box_f.cc @@ -6,6 +6,7 @@ #include <algorithm> +#include "base/logging.h" #include "base/strings/stringprintf.h" namespace gfx { @@ -24,6 +25,24 @@ bool BoxF::IsEmpty() const { (height_ == 0 && depth_ == 0); } +void BoxF::ExpandTo(const Point3F& min, const Point3F& max) { + DCHECK_LE(min.x(), max.x()); + DCHECK_LE(min.y(), max.y()); + DCHECK_LE(min.z(), max.z()); + + float min_x = std::min(x(), min.x()); + float min_y = std::min(y(), min.y()); + float min_z = std::min(z(), min.z()); + float max_x = std::max(right(), max.x()); + float max_y = std::max(bottom(), max.y()); + float max_z = std::max(front(), max.z()); + + origin_.SetPoint(min_x, min_y, min_z); + width_ = max_x - min_x; + height_ = max_y - min_y; + depth_ = max_z - min_z; +} + void BoxF::Union(const BoxF& box) { if (IsEmpty()) { *this = box; @@ -31,18 +50,15 @@ void BoxF::Union(const BoxF& box) { } if (box.IsEmpty()) return; + ExpandTo(box); +} - float min_x = std::min(x(), box.x()); - float min_y = std::min(y(), box.y()); - float min_z = std::min(z(), box.z()); - float max_x = std::max(right(), box.right()); - float max_y = std::max(bottom(), box.bottom()); - float max_z = std::max(front(), box.front()); +void BoxF::ExpandTo(const Point3F& point) { + ExpandTo(point, point); +} - origin_.SetPoint(min_x, min_y, min_z); - width_ = max_x - min_x; - height_ = max_y - min_y; - depth_ = max_z - min_z; +void BoxF::ExpandTo(const BoxF& box) { + ExpandTo(box.origin(), gfx::Point3F(box.right(), box.bottom(), box.front())); } BoxF UnionBoxes(const BoxF& a, const BoxF& b) { diff --git a/chromium/ui/gfx/box_f.h b/chromium/ui/gfx/box_f.h index 01063b19712..73e0972f662 100644 --- a/chromium/ui/gfx/box_f.h +++ b/chromium/ui/gfx/box_f.h @@ -12,7 +12,7 @@ namespace gfx { // A 3d version of gfx::RectF, with the positive z-axis pointed towards // the camera. -class UI_EXPORT BoxF { +class GFX_EXPORT BoxF { public: BoxF() : width_(0.f), @@ -94,14 +94,32 @@ class UI_EXPORT BoxF { 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_; }; -UI_EXPORT BoxF UnionBoxes(const BoxF& a, const BoxF& b); +GFX_EXPORT BoxF UnionBoxes(const BoxF& a, const BoxF& b); inline BoxF ScaleBox(const BoxF& b, float x_scale, diff --git a/chromium/ui/gfx/box_unittest.cc b/chromium/ui/gfx/box_unittest.cc index 0e944ec5a12..db894cae1cd 100644 --- a/chromium/ui/gfx/box_unittest.cc +++ b/chromium/ui/gfx/box_unittest.cc @@ -78,6 +78,39 @@ TEST(BoxTest, Union) { UnionBoxes(box3, box2).ToString()); } +TEST(BoxTest, ExpandTo) { + BoxF box1; + BoxF box2(0.f, 0.f, 0.f, 1.f, 1.f, 1.f); + BoxF box3(1.f, 1.f, 1.f, 0.f, 0.f, 0.f); + + Point3F point1(0.5f, 0.5f, 0.5f); + Point3F point2(-0.5f, -0.5f, -0.5f); + + BoxF expected1_1(0.f, 0.f, 0.f, 0.5f, 0.5f, 0.5f); + BoxF expected1_2(-0.5f, -0.5f, -0.5f, 1.f, 1.f, 1.f); + + BoxF expected2_1 = box2; + BoxF expected2_2(-0.5f, -0.5f, -0.5f, 1.5f, 1.5f, 1.5f); + + BoxF expected3_1(0.5f, 0.5f, 0.5f, 0.5f, 0.5f, 0.5f); + BoxF expected3_2(-0.5f, -0.5f, -0.5f, 1.5f, 1.5f, 1.5f); + + box1.ExpandTo(point1); + EXPECT_EQ(expected1_1.ToString(), box1.ToString()); + box1.ExpandTo(point2); + EXPECT_EQ(expected1_2.ToString(), box1.ToString()); + + box2.ExpandTo(point1); + EXPECT_EQ(expected2_1.ToString(), box2.ToString()); + box2.ExpandTo(point2); + EXPECT_EQ(expected2_2.ToString(), box2.ToString()); + + box3.ExpandTo(point1); + EXPECT_EQ(expected3_1.ToString(), box3.ToString()); + box3.ExpandTo(point2); + EXPECT_EQ(expected3_2.ToString(), box3.ToString()); +} + TEST(BoxTest, Scale) { BoxF box1(2.f, 3.f, 4.f, 5.f, 6.f, 7.f); diff --git a/chromium/ui/gfx/canvas.cc b/chromium/ui/gfx/canvas.cc index b59d2a0d888..b89efa9e2b7 100644 --- a/chromium/ui/gfx/canvas.cc +++ b/chromium/ui/gfx/canvas.cc @@ -4,6 +4,7 @@ #include "ui/gfx/canvas.h" +#include <cmath> #include <limits> #include "base/i18n/rtl.h" @@ -23,11 +24,10 @@ namespace gfx { -Canvas::Canvas(const Size& size, ui::ScaleFactor scale_factor, bool is_opaque) - : scale_factor_(scale_factor), +Canvas::Canvas(const Size& size, float image_scale, bool is_opaque) + : image_scale_(image_scale), canvas_(NULL) { - Size pixel_size = ToCeiledSize( - ScaleSize(size, ui::GetScaleFactorScale(scale_factor))); + Size pixel_size = ToCeiledSize(ScaleSize(size, image_scale)); owned_canvas_ = skia::AdoptRef(skia::CreatePlatformCanvas(pixel_size.width(), pixel_size.height(), is_opaque)); @@ -39,24 +39,24 @@ Canvas::Canvas(const Size& size, ui::ScaleFactor scale_factor, bool is_opaque) owned_canvas_->clear(SkColorSetARGB(0, 0, 0, 0)); #endif - SkScalar scale = SkFloatToScalar(ui::GetScaleFactorScale(scale_factor)); - canvas_->scale(scale, scale); + SkScalar scale_scalar = SkFloatToScalar(image_scale); + canvas_->scale(scale_scalar, scale_scalar); } Canvas::Canvas(const ImageSkiaRep& image_rep, bool is_opaque) - : scale_factor_(image_rep.scale_factor()), + : image_scale_(image_rep.scale()), owned_canvas_(skia::AdoptRef( skia::CreatePlatformCanvas(image_rep.pixel_width(), image_rep.pixel_height(), is_opaque))), canvas_(owned_canvas_.get()) { - SkScalar scale = SkFloatToScalar(ui::GetScaleFactorScale(scale_factor_)); - canvas_->scale(scale, scale); + SkScalar scale_scalar = SkFloatToScalar(image_scale_); + canvas_->scale(scale_scalar, scale_scalar); DrawImageInt(ImageSkia(image_rep), 0, 0); } Canvas::Canvas() - : scale_factor_(ui::SCALE_FACTOR_100P), + : image_scale_(1.0), owned_canvas_(skia::AdoptRef(skia::CreatePlatformCanvas(0, 0, false))), canvas_(owned_canvas_.get()) { } @@ -66,22 +66,36 @@ Canvas::~Canvas() { // static Canvas* Canvas::CreateCanvasWithoutScaling(SkCanvas* canvas, - ui::ScaleFactor scale_factor) { - return new Canvas(canvas, scale_factor); + float image_scale) { + return new Canvas(canvas, image_scale); } void Canvas::RecreateBackingCanvas(const Size& size, - ui::ScaleFactor scale_factor, + float image_scale, bool is_opaque) { - scale_factor_ = scale_factor; - Size pixel_size = ToFlooredSize( - ScaleSize(size, ui::GetScaleFactorScale(scale_factor))); + image_scale_ = image_scale; + Size pixel_size = ToFlooredSize(ScaleSize(size, image_scale)); owned_canvas_ = skia::AdoptRef(skia::CreatePlatformCanvas(pixel_size.width(), pixel_size.height(), is_opaque)); canvas_ = owned_canvas_.get(); - SkScalar scale = SkFloatToScalar(ui::GetScaleFactorScale(scale_factor_)); - canvas_->scale(scale, scale); + SkScalar scale_scalar = SkFloatToScalar(image_scale); + canvas_->scale(scale_scalar, scale_scalar); +} + +// static +void Canvas::SizeStringInt(const base::string16& text, + const FontList& font_list, + int* width, + int* height, + int line_height, + int flags) { + float fractional_width = *width; + float factional_height = *height; + SizeStringFloat(text, font_list, &fractional_width, + &factional_height, line_height, flags); + *width = std::ceil(fractional_width); + *height = std::ceil(factional_height); } // static @@ -103,6 +117,14 @@ int Canvas::GetStringWidth(const base::string16& text, } // static +float Canvas::GetStringWidthF(const base::string16& text, + const FontList& font_list) { + float width = 0, height = 0; + SizeStringFloat(text, font_list, &width, &height, 0, NO_ELLIPSIS); + return width; +} + +// 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); @@ -136,7 +158,7 @@ ImageSkiaRep Canvas::ExtractImageRep() const { SkBitmap result; device_bitmap.copyTo(&result, SkBitmap::kARGB_8888_Config); - return ImageSkiaRep(result, scale_factor_); + return ImageSkiaRep(result, image_scale_); } void Canvas::DrawDashedRect(const Rect& rect, SkColor color) { @@ -310,6 +332,22 @@ void Canvas::DrawFocusRect(const Rect& rect) { DrawDashedRect(rect, SK_ColorGRAY); } +void Canvas::DrawSolidFocusRect(const Rect& rect, SkColor color) { + SkPaint paint; + paint.setColor(color); + paint.setStrokeWidth(SkIntToScalar(1)); + // Note: We cannot use DrawRect since it would create a path and fill it which + // would cause problems near the edge of the canvas. + int x1 = std::min(rect.x(), rect.right()); + int x2 = std::max(rect.x(), rect.right()); + int y1 = std::min(rect.y(), rect.bottom()); + int y2 = std::max(rect.y(), rect.bottom()); + DrawLine(Point(x1, y1), Point(x2, y1), paint); + DrawLine(Point(x1, y2), Point(x2, y2), paint); + DrawLine(Point(x1, y1), Point(x1, y2), paint); + DrawLine(Point(x2, y1), Point(x2, y2 + 1), paint); +} + void Canvas::DrawImageInt(const ImageSkia& image, int x, int y) { SkPaint paint; DrawImageInt(image, x, y, paint); @@ -329,7 +367,7 @@ void Canvas::DrawImageInt(const ImageSkia& image, if (image_rep.is_null()) return; const SkBitmap& bitmap = image_rep.sk_bitmap(); - float bitmap_scale = image_rep.GetScale(); + float bitmap_scale = image_rep.scale(); canvas_->save(); canvas_->scale(SkFloatToScalar(1.0f / bitmap_scale), @@ -392,7 +430,7 @@ void Canvas::DrawImageInt(const ImageSkia& image, if (src_w == dest_w && src_h == dest_h && user_scale_x == 1.0f && user_scale_y == 1.0f && - image_rep.scale_factor() == ui::SCALE_FACTOR_100P) { + 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 }; @@ -574,8 +612,8 @@ void Canvas::Transform(const gfx::Transform& transform) { canvas_->concat(transform.matrix()); } -Canvas::Canvas(SkCanvas* canvas, ui::ScaleFactor scale_factor) - : scale_factor_(scale_factor), +Canvas::Canvas(SkCanvas* canvas, float image_scale) + : image_scale_(image_scale), owned_canvas_(), canvas_(canvas) { DCHECK(canvas); @@ -601,7 +639,7 @@ const ImageSkiaRep& Canvas::GetImageRepToPaint( const ImageSkia& image, float user_additional_scale_x, float user_additional_scale_y) const { - const ImageSkiaRep& image_rep = image.GetRepresentation(scale_factor_); + const ImageSkiaRep& image_rep = image.GetRepresentation(image_scale_); if (!image_rep.is_null()) { SkMatrix m = canvas_->getTotalMatrix(); @@ -610,7 +648,7 @@ const ImageSkiaRep& Canvas::GetImageRepToPaint( float scale_y = SkScalarToFloat(SkScalarAbs(m.getScaleY())) * user_additional_scale_y; - float bitmap_scale = image_rep.GetScale(); + float bitmap_scale = image_rep.scale(); if (scale_x < bitmap_scale || scale_y < bitmap_scale) const_cast<SkBitmap&>(image_rep.sk_bitmap()).buildMipMap(); } diff --git a/chromium/ui/gfx/canvas.h b/chromium/ui/gfx/canvas.h index c8996a234a8..f8193f1134c 100644 --- a/chromium/ui/gfx/canvas.h +++ b/chromium/ui/gfx/canvas.h @@ -38,12 +38,11 @@ class Transform; // source and destination colors are combined. Unless otherwise specified, // the variant that does not take a SkXfermode::Mode uses a transfer mode // of kSrcOver_Mode. -class UI_EXPORT Canvas { +class GFX_EXPORT Canvas { public: enum TruncateFadeMode { TruncateFadeTail, TruncateFadeHead, - TruncateFadeHeadAndTail, }; // Specifies the alignment for text rendered with the DrawStringInt method. @@ -90,34 +89,34 @@ class UI_EXPORT Canvas { NO_SUBPIXEL_RENDERING = 1 << 10, }; - // Creates an empty canvas with scale factor of 1x. + // Creates an empty canvas with image_scale of 1x. Canvas(); - // Creates canvas with provided DIP |size| and |scale_factor|. + // Creates canvas with provided DIP |size| and |image_scale|. // If this canvas is not opaque, it's explicitly cleared to transparent before // being returned. - Canvas(const Size& size, ui::ScaleFactor scale_factor, bool is_opaque); + Canvas(const Size& size, float image_scale, bool is_opaque); - // Constructs a canvas with the size and the scale factor of the - // provided |image_rep|, and draws the |image_rep| into it. + // Constructs a canvas with the size and the image_scale of the provided + // |image_rep|, and draws the |image_rep| into it. Canvas(const ImageSkiaRep& image_rep, bool is_opaque); virtual ~Canvas(); - // Creates a Canvas backed by an |sk_canvas| with |scale_factor|. - // |sk_canvas| is assumed to be already scaled based on |scale_factor| + // Creates a Canvas backed by an |sk_canvas| with |image_scale_|. + // |sk_canvas| is assumed to be already scaled based on |image_scale| // so no additional scaling is applied. static Canvas* CreateCanvasWithoutScaling(SkCanvas* sk_canvas, - ui::ScaleFactor scale_factor); + float image_scale); - // Recreates the backing platform canvas with DIP |size| and |scale_factor|. + // Recreates the backing platform canvas with DIP |size| and |image_scale_|. // If the canvas is not opaque, it is explicitly cleared. // This method is public so that canvas_skia_paint can recreate the platform // canvas after having initialized the canvas. - // TODO(pkotwicz): Push the scale factor into skia::PlatformCanvas such that + // TODO(pkotwicz): Push the image_scale into skia::PlatformCanvas such that // this method can be private. void RecreateBackingCanvas(const Size& size, - ui::ScaleFactor scale_factor, + float image_scale, bool is_opaque); // Compute the size required to draw some text with the provided fonts. @@ -139,6 +138,15 @@ class UI_EXPORT Canvas { int line_height, int flags); + // This is same as SizeStringInt except that fractional size is returned. + // See comment in GetStringWidthF for its usage. + static void SizeStringFloat(const base::string16& text, + const FontList& font_list, + float* width, + float* height, + int line_height, + int flags); + // Returns the number of horizontal pixels needed to display the specified // |text| with |font_list|. static int GetStringWidth(const base::string16& text, @@ -146,6 +154,14 @@ class UI_EXPORT Canvas { // 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 + // summed up. This is because GetStringWidth returns the ceiled width and + // adding multiple ceiled widths could cause more precision loss for certain + // platform like Mac where the fractioal width is used. + static float GetStringWidthF(const base::string16& text, + const FontList& font_list); + // 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 @@ -393,6 +409,10 @@ class UI_EXPORT Canvas { // Draws a dotted gray rectangle used for focus purposes. void DrawFocusRect(const Rect& rect); + // Draws a |rect| in the specified region with the specified |color| with a + // with of one logical pixel which might be more device pixels. + void DrawSolidFocusRect(const Rect& rect, SkColor color); + // Tiles the image in the specified region. // Parameters are specified relative to current canvas scale not in pixels. // Thus, |x| is 2 pixels if canvas scale = 2 & |x| = 1. @@ -429,38 +449,33 @@ class UI_EXPORT Canvas { // Apply transformation on the canvas. void Transform(const Transform& transform); - // Draws the given string with the beginning and/or the end using a fade - // gradient. When truncating the head - // |desired_characters_to_truncate_from_head| specifies the maximum number of - // characters that can be truncated. + // Draws the given string with the beginning or the end using a fade gradient. void DrawFadeTruncatingStringRect( const base::string16& text, TruncateFadeMode truncate_mode, - size_t desired_characters_to_truncate_from_head, const FontList& font_list, SkColor color, const Rect& display_rect); - // Obsolete version. Use the above version which takes FontList. - void DrawFadeTruncatingString( + void DrawFadeTruncatingStringRectWithFlags( const base::string16& text, TruncateFadeMode truncate_mode, - size_t desired_characters_to_truncate_from_head, - const Font& font, + const FontList& font_list, SkColor color, - const Rect& display_rect); + const Rect& display_rect, + int flags); skia::PlatformCanvas* platform_canvas() const { return owned_canvas_.get(); } SkCanvas* sk_canvas() const { return canvas_; } - ui::ScaleFactor scale_factor() const { return scale_factor_; } + float image_scale() const { return image_scale_; } private: - Canvas(SkCanvas* canvas, ui::ScaleFactor scale_factor); + Canvas(SkCanvas* canvas, float image_scale); // Test whether the provided rectangle intersects the current clip rect. bool IntersectsClipRectInt(int x, int y, int w, int h); bool IntersectsClipRect(const Rect& rect); - // Returns the image rep which best matches the canvas |scale_factor_|. + // 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. // @@ -473,8 +488,8 @@ class UI_EXPORT Canvas { // The device scale factor at which drawing on this canvas occurs. // An additional scale can be applied via Canvas::Scale(). However, - // Canvas::Scale() does not affect |scale_factor_|. - ui::ScaleFactor scale_factor_; + // Canvas::Scale() does not affect |image_scale_|. + float image_scale_; skia::RefPtr<skia::PlatformCanvas> owned_canvas_; SkCanvas* canvas_; diff --git a/chromium/ui/gfx/canvas_android.cc b/chromium/ui/gfx/canvas_android.cc index 54e45f7653a..61e3a3af14c 100644 --- a/chromium/ui/gfx/canvas_android.cc +++ b/chromium/ui/gfx/canvas_android.cc @@ -9,12 +9,12 @@ namespace gfx { // static -void Canvas::SizeStringInt(const base::string16& text, - const FontList& font_list, - int* width, - int* height, - int line_height, - int flags) { +void Canvas::SizeStringFloat(const base::string16& text, + const FontList& font_list, + float* width, + float* height, + int line_height, + int flags) { NOTIMPLEMENTED(); } diff --git a/chromium/ui/gfx/canvas_paint.h b/chromium/ui/gfx/canvas_paint.h index 4ae8b7c0229..4d38df38ac9 100644 --- a/chromium/ui/gfx/canvas_paint.h +++ b/chromium/ui/gfx/canvas_paint.h @@ -17,7 +17,7 @@ class CanvasPaint { public: // Creates a canvas that paints to |view| when it is destroyed. The canvas is // sized to the client area of |view|. - UI_EXPORT static CanvasPaint* CreateCanvasPaint(gfx::NativeView view); + GFX_EXPORT static CanvasPaint* CreateCanvasPaint(gfx::NativeView view); virtual ~CanvasPaint() {} diff --git a/chromium/ui/gfx/canvas_paint_gtk.cc b/chromium/ui/gfx/canvas_paint_gtk.cc index 4c185c02e03..aef6fc982e3 100644 --- a/chromium/ui/gfx/canvas_paint_gtk.cc +++ b/chromium/ui/gfx/canvas_paint_gtk.cc @@ -10,6 +10,8 @@ namespace gfx { +// CanvasSkiaPaint + CanvasSkiaPaint::CanvasSkiaPaint(GdkEventExpose* event) : context_(NULL), window_(event->window), @@ -52,8 +54,7 @@ CanvasSkiaPaint::~CanvasSkiaPaint() { void CanvasSkiaPaint::Init(bool opaque) { GdkRectangle bounds = rectangle(); - RecreateBackingCanvas(gfx::Size(bounds.width, bounds.height), - ui::SCALE_FACTOR_100P, opaque); + RecreateBackingCanvas(Size(bounds.width, bounds.height), 1.0f, opaque); skia::PlatformCanvas* canvas = platform_canvas(); @@ -64,6 +65,43 @@ void CanvasSkiaPaint::Init(bool opaque) { 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 index 889f30895b4..487db79f47a 100644 --- a/chromium/ui/gfx/canvas_paint_gtk.h +++ b/chromium/ui/gfx/canvas_paint_gtk.h @@ -17,7 +17,7 @@ namespace gfx { // 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 UI_EXPORT CanvasSkiaPaint : public Canvas { +class GFX_EXPORT CanvasSkiaPaint : public Canvas { public: // This constructor assumes the result is opaque. explicit CanvasSkiaPaint(GdkEventExpose* event); @@ -57,6 +57,46 @@ class UI_EXPORT CanvasSkiaPaint : public Canvas { 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_paint_mac.h b/chromium/ui/gfx/canvas_paint_mac.h index 16d74109f65..f3658c33f1f 100644 --- a/chromium/ui/gfx/canvas_paint_mac.h +++ b/chromium/ui/gfx/canvas_paint_mac.h @@ -17,7 +17,7 @@ namespace gfx { // graphics context. On construction, it will set up a context for painting // into, and on destruction, it will commit it to the current context. // Note: The created context is always inialized to (0, 0, 0, 0). -class UI_EXPORT CanvasSkiaPaint : public Canvas { +class GFX_EXPORT CanvasSkiaPaint : public Canvas { public: // This constructor assumes the result is opaque. explicit CanvasSkiaPaint(NSRect dirtyRect); diff --git a/chromium/ui/gfx/canvas_paint_mac.mm b/chromium/ui/gfx/canvas_paint_mac.mm index c8796afedae..8ba697d1091 100644 --- a/chromium/ui/gfx/canvas_paint_mac.mm +++ b/chromium/ui/gfx/canvas_paint_mac.mm @@ -58,9 +58,8 @@ void CanvasSkiaPaint::Init(bool opaque) { // Assume that the x scale and the y scale are the same. CGFloat scale = scaled_unit_rect.size.width; - ui::ScaleFactor scale_factor = ui::GetScaleFactorFromScale(scale); gfx::Size size(NSWidth(rectangle_), NSHeight(rectangle_)); - RecreateBackingCanvas(size, scale_factor, opaque); + RecreateBackingCanvas(size, scale, opaque); skia::PlatformCanvas* canvas = platform_canvas(); canvas->clear(SkColorSetARGB(0, 0, 0, 0)); @@ -74,4 +73,4 @@ void CanvasSkiaPaint::Init(bool opaque) { } // namespace skia - + diff --git a/chromium/ui/gfx/canvas_paint_win.cc b/chromium/ui/gfx/canvas_paint_win.cc index 71c836724a2..7d20fbcd1c8 100644 --- a/chromium/ui/gfx/canvas_paint_win.cc +++ b/chromium/ui/gfx/canvas_paint_win.cc @@ -56,7 +56,7 @@ void CanvasSkiaPaint::Init(bool opaque) { const int height = ps_.rcPaint.bottom - ps_.rcPaint.top; RecreateBackingCanvas(gfx::Size(width, height), - ui::GetScaleFactorFromScale(gfx::win::GetDeviceScaleFactor()), + gfx::win::GetDeviceScaleFactor(), opaque); skia::PlatformCanvas* canvas = platform_canvas(); diff --git a/chromium/ui/gfx/canvas_paint_win.h b/chromium/ui/gfx/canvas_paint_win.h index c5d3aee3211..9028cbac6f3 100644 --- a/chromium/ui/gfx/canvas_paint_win.h +++ b/chromium/ui/gfx/canvas_paint_win.h @@ -33,7 +33,7 @@ namespace gfx { // return 0; // } // Note: The created context is always inialized to (0, 0, 0, 0). -class UI_EXPORT CanvasSkiaPaint : public Canvas { +class GFX_EXPORT CanvasSkiaPaint : public Canvas { public: // This constructor assumes the canvas is opaque. CanvasSkiaPaint(HWND hwnd, HDC dc, const PAINTSTRUCT& ps); diff --git a/chromium/ui/gfx/canvas_skia.cc b/chromium/ui/gfx/canvas_skia.cc index ef8ee3625a7..1ad60ba2b04 100644 --- a/chromium/ui/gfx/canvas_skia.cc +++ b/chromium/ui/gfx/canvas_skia.cc @@ -20,6 +20,7 @@ namespace gfx { namespace { +#if defined(OS_WIN) // If necessary, wraps |text| with RTL/LTR directionality characters based on // |flags| and |text| content. // Returns true if the text will be rendered right-to-left. @@ -52,6 +53,7 @@ bool AdjustStringDirection(int flags, base::string16* text) { // locales it will be handled by the if statement above). return false; } +#endif // defined(OS_WIN) // Checks each pixel immediately adjacent to the given pixel in the bitmap. If // any of them are not the halo color, returns true. This defines the halo of @@ -152,31 +154,17 @@ void UpdateRenderText(const Rect& rect, render_text->SetStyle(UNDERLINE, (font_style & Font::UNDERLINE) != 0); } -// Returns updated |flags| to match platform-specific expected behavior. -int AdjustPlatformSpecificFlags(const base::string16& text, int flags) { -#if defined(OS_LINUX) - // TODO(asvitkine): ash/tooltips/tooltip_controller.cc adds \n's to the string - // without passing MULTI_LINE. - if (text.find('\n') != base::string16::npos) - flags |= Canvas::MULTI_LINE; -#endif - - return flags; -} - } // namespace // static -void Canvas::SizeStringInt(const base::string16& text, - const FontList& font_list, - int* width, int* height, - int line_height, - int flags) { +void Canvas::SizeStringFloat(const base::string16& text, + const FontList& font_list, + float* width, float* height, + int line_height, + int flags) { DCHECK_GE(*width, 0); DCHECK_GE(*height, 0); - flags = AdjustPlatformSpecificFlags(text, flags); - base::string16 adjusted_text = text; #if defined(OS_WIN) AdjustStringDirection(flags, &adjusted_text); @@ -198,12 +186,12 @@ void Canvas::SizeStringInt(const base::string16& text, UpdateRenderText(rect, base::string16(), font_list, flags, 0, render_text.get()); - int h = 0; - int w = 0; + float h = 0; + float w = 0; for (size_t i = 0; i < strings.size(); ++i) { StripAcceleratorChars(flags, &strings[i]); render_text->SetText(strings[i]); - const Size& string_size = render_text->GetStringSize(); + const SizeF& string_size = render_text->GetStringSizeF(); w = std::max(w, string_size.width()); h += (i > 0 && line_height > 0) ? line_height : string_size.height(); } @@ -222,7 +210,7 @@ void Canvas::SizeStringInt(const base::string16& text, StripAcceleratorChars(flags, &adjusted_text); UpdateRenderText(rect, adjusted_text, font_list, flags, 0, render_text.get()); - const Size& string_size = render_text->GetStringSize(); + const SizeF& string_size = render_text->GetStringSizeF(); *width = string_size.width(); *height = string_size.height(); } @@ -239,8 +227,6 @@ void Canvas::DrawStringRectWithShadows(const base::string16& text, if (!IntersectsClipRect(text_bounds)) return; - flags = AdjustPlatformSpecificFlags(text, flags); - Rect clip_rect(text_bounds); clip_rect.Inset(ShadowValue::GetMargin(shadows)); @@ -350,7 +336,7 @@ void Canvas::DrawStringRectWithHalo(const base::string16& text, // Create a temporary buffer filled with the halo color. It must leave room // for the 1-pixel border around the text. Size size(display_rect.width() + 2, display_rect.height() + 2); - Canvas text_canvas(size, scale_factor(), true); + Canvas text_canvas(size, image_scale(), false); SkPaint bkgnd_paint; bkgnd_paint.setColor(halo_color); text_canvas.DrawRect(Rect(size), bkgnd_paint); @@ -381,19 +367,27 @@ void Canvas::DrawStringRectWithHalo(const base::string16& text, // Draw the halo bitmap with blur. ImageSkia text_image = ImageSkia(ImageSkiaRep(text_bitmap, - text_canvas.scale_factor())); + text_canvas.image_scale())); DrawImageInt(text_image, display_rect.x() - 1, display_rect.y() - 1); } void Canvas::DrawFadeTruncatingStringRect( const base::string16& text, TruncateFadeMode truncate_mode, - size_t desired_characters_to_truncate_from_head, const FontList& font_list, SkColor color, const Rect& display_rect) { - int flags = NO_ELLIPSIS; + 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) { // 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); @@ -401,8 +395,8 @@ void Canvas::DrawFadeTruncatingStringRect( } scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); - base::string16 clipped_text = text; - const bool is_rtl = AdjustStringDirection(flags, &clipped_text); + const bool is_rtl = base::i18n::GetFirstStrongCharacterDirection(text) == + base::i18n::RIGHT_TO_LEFT; switch (truncate_mode) { case TruncateFadeTail: @@ -415,26 +409,6 @@ void Canvas::DrawFadeTruncatingStringRect( if (!is_rtl) flags |= TEXT_ALIGN_RIGHT; break; - case TruncateFadeHeadAndTail: - DCHECK_GT(desired_characters_to_truncate_from_head, 0u); - // Due to the fade effect the first character is hard to see. - // We want to make sure that the first character starting at - // |desired_characters_to_truncate_from_head| is readable so we reduce - // the offset by a little bit. - desired_characters_to_truncate_from_head = - std::max<int>(0, desired_characters_to_truncate_from_head - 2); - - if (desired_characters_to_truncate_from_head) { - // Make sure to clip the text at a UTF16 boundary. - U16_SET_CP_LIMIT(text.data(), 0, - desired_characters_to_truncate_from_head, - text.length()); - clipped_text = text.substr(desired_characters_to_truncate_from_head); - } - - render_text->set_fade_tail(true); - render_text->set_fade_head(true); - break; } // Default to left alignment unless right alignment was chosen above. @@ -442,8 +416,7 @@ void Canvas::DrawFadeTruncatingStringRect( flags |= TEXT_ALIGN_LEFT; Rect rect = display_rect; - UpdateRenderText(rect, clipped_text, font_list, flags, color, - render_text.get()); + UpdateRenderText(rect, text, font_list, flags, color, render_text.get()); const int line_height = render_text->GetStringSize().height(); // Center the text vertically. @@ -457,16 +430,4 @@ void Canvas::DrawFadeTruncatingStringRect( canvas_->restore(); } -void Canvas::DrawFadeTruncatingString( - const base::string16& text, - TruncateFadeMode truncate_mode, - size_t desired_characters_to_truncate_from_head, - const Font& font, - SkColor color, - const Rect& display_rect) { - DrawFadeTruncatingStringRect(text, truncate_mode, - desired_characters_to_truncate_from_head, - FontList(font), color, display_rect); -} - } // namespace gfx diff --git a/chromium/ui/gfx/canvas_unittest_mac.mm b/chromium/ui/gfx/canvas_unittest_mac.mm index d607218c64f..7aff64b07a8 100644 --- a/chromium/ui/gfx/canvas_unittest_mac.mm +++ b/chromium/ui/gfx/canvas_unittest_mac.mm @@ -18,25 +18,16 @@ namespace gfx { namespace { -// Mac-specific code for string size computations. This is a verbatim copy -// of the old implementation that used to be in canvas_mac.mm. -void CanvasMac_SizeStringInt(const base::string16& text, - const FontList& font_list, - int* width, - int* height, - int line_height, - int flags) { - DLOG_IF(WARNING, line_height != 0) << "Line heights not implemented."; - DLOG_IF(WARNING, flags & Canvas::MULTI_LINE) << "Multi-line not implemented."; - +// Returns the pixel width of the string via calling the native method +// -sizeWithAttributes. +float GetStringNativeWidth(const base::string16& text, + const FontList& font_list) { NSFont* native_font = font_list.GetPrimaryFont().GetNativeFont(); NSString* ns_string = base::SysUTF16ToNSString(text); NSDictionary* attributes = [NSDictionary dictionaryWithObject:native_font forKey:NSFontAttributeName]; - NSSize string_size = [ns_string sizeWithAttributes:attributes]; - *width = std::ceil(string_size.width); - *height = font_list.GetHeight(); + return [ns_string sizeWithAttributes:attributes].width; } } // namespace @@ -49,30 +40,31 @@ class CanvasTestMac : public testing::Test { // without specified line height, since that is all the platform // implementation supports. void CompareSizes(const char* text) { - const int kReallyLargeNumber = 12345678; + const float kReallyLargeNumber = 12345678; FontList font_list(font_); base::string16 text16 = base::UTF8ToUTF16(text); - int mac_width = kReallyLargeNumber; - int mac_height = kReallyLargeNumber; - CanvasMac_SizeStringInt(text16, font_list, &mac_width, &mac_height, 0, 0); + float mac_width = GetStringNativeWidth(text16, font_list); + int mac_height = font_list.GetHeight(); - int canvas_width = kReallyLargeNumber; - int canvas_height = kReallyLargeNumber; - Canvas::SizeStringInt( + float canvas_width = kReallyLargeNumber; + float canvas_height = kReallyLargeNumber; + Canvas::SizeStringFloat( text16, font_list, &canvas_width, &canvas_height, 0, 0); EXPECT_NE(kReallyLargeNumber, mac_width) << "no width for " << text; EXPECT_NE(kReallyLargeNumber, mac_height) << "no height for " << text; EXPECT_EQ(mac_width, canvas_width) << " width for " << text; - EXPECT_EQ(mac_height, canvas_height) << " height for " << text; + // FontList::GetHeight returns a truncated height. + EXPECT_EQ(mac_height, + static_cast<int>(canvas_height)) << " height for " << text; } private: Font font_; }; - // Tests that Canvas' SizeStringInt yields result consistent with a native + // Tests that Canvas' SizeStringFloat yields result consistent with a native // implementation. TEST_F(CanvasTestMac, StringSizeIdenticalForSkia) { CompareSizes(""); @@ -81,4 +73,16 @@ class CanvasTestMac : public testing::Test { CompareSizes("This is a complete sentence."); } +TEST_F(CanvasTestMac, FractionalWidth) { + const float kReallyLargeNumber = 12345678; + float width = kReallyLargeNumber; + float height = kReallyLargeNumber; + + FontList font_list; + Canvas::SizeStringFloat( + base::UTF8ToUTF16("Test"), font_list, &width, &height, 0, 0); + + EXPECT_GT(width, static_cast<int>(width)); +} + } // namespace gfx diff --git a/chromium/ui/gfx/codec/jpeg_codec.h b/chromium/ui/gfx/codec/jpeg_codec.h index b6b7088c361..8219221283e 100644 --- a/chromium/ui/gfx/codec/jpeg_codec.h +++ b/chromium/ui/gfx/codec/jpeg_codec.h @@ -18,7 +18,7 @@ namespace gfx { // which has an inconvenient interface for callers. This is only used for UI // elements, WebKit has its own more complicated JPEG decoder which handles, // among other things, partially downloaded data. -class UI_EXPORT JPEGCodec { +class GFX_EXPORT JPEGCodec { public: enum ColorFormat { // 3 bytes per pixel (packed), in RGB order regardless of endianness. diff --git a/chromium/ui/gfx/codec/png_codec.cc b/chromium/ui/gfx/codec/png_codec.cc index 30e4eb6d653..b3f4345343f 100644 --- a/chromium/ui/gfx/codec/png_codec.cc +++ b/chromium/ui/gfx/codec/png_codec.cc @@ -465,36 +465,12 @@ bool PNGCodec::Decode(const unsigned char* input, size_t input_size, } // Set the bitmap's opaqueness based on what we saw. - bitmap->setIsOpaque(state.is_opaque); + bitmap->setAlphaType(state.is_opaque ? + kOpaque_SkAlphaType : kPremul_SkAlphaType); return true; } -// static -SkBitmap* PNGCodec::CreateSkBitmapFromBGRAFormat( - const std::vector<unsigned char>& bgra, int width, int height) { - SkBitmap* bitmap = new SkBitmap(); - bitmap->setConfig(SkBitmap::kARGB_8888_Config, width, height); - bitmap->allocPixels(); - - bool opaque = false; - unsigned char* bitmap_data = - reinterpret_cast<unsigned char*>(bitmap->getAddr32(0, 0)); - for (int i = width * height * 4 - 4; i >= 0; i -= 4) { - unsigned char alpha = bgra[i + 3]; - if (!opaque && alpha != 255) { - opaque = false; - } - bitmap_data[i + 3] = alpha; - bitmap_data[i] = (bgra[i] * alpha) >> 8; - bitmap_data[i + 1] = (bgra[i + 1] * alpha) >> 8; - bitmap_data[i + 2] = (bgra[i + 2] * alpha) >> 8; - } - - bitmap->setIsOpaque(opaque); - return bitmap; -} - // Encoder -------------------------------------------------------------------- // // This section of the code is based on nsPNGEncoder.cpp in Mozilla diff --git a/chromium/ui/gfx/codec/png_codec.h b/chromium/ui/gfx/codec/png_codec.h index 86f170d359f..abb3eaab32c 100644 --- a/chromium/ui/gfx/codec/png_codec.h +++ b/chromium/ui/gfx/codec/png_codec.h @@ -23,7 +23,7 @@ class Size; // isn't as robust as would be required for a browser (see Decode() for more). // WebKit has its own more complicated PNG decoder which handles, among other // things, partially downloaded data. -class UI_EXPORT PNGCodec { +class GFX_EXPORT PNGCodec { public: enum ColorFormat { // 3 bytes per pixel (packed), in RGB order regardless of endianness. @@ -43,7 +43,7 @@ class UI_EXPORT PNGCodec { }; // Represents a comment in the tEXt ancillary chunk of the png. - struct UI_EXPORT Comment { + struct GFX_EXPORT Comment { Comment(const std::string& k, const std::string& t); ~Comment(); @@ -114,11 +114,6 @@ class UI_EXPORT PNGCodec { static bool Decode(const unsigned char* input, size_t input_size, SkBitmap* bitmap); - // Create a SkBitmap from a decoded BGRA DIB. The caller owns the returned - // SkBitmap. - static SkBitmap* CreateSkBitmapFromBGRAFormat( - const std::vector<unsigned char>& bgra, int width, int height); - private: DISALLOW_COPY_AND_ASSIGN(PNGCodec); }; diff --git a/chromium/ui/gfx/color_analysis.h b/chromium/ui/gfx/color_analysis.h index 797b4f94663..dcbfabc9d77 100644 --- a/chromium/ui/gfx/color_analysis.h +++ b/chromium/ui/gfx/color_analysis.h @@ -25,7 +25,7 @@ namespace color_utils { // Note: Samplers should be deterministic, as the same image may be analyzed // twice with two sampler instances and the results displayed side-by-side // to the user. -class UI_EXPORT KMeanImageSampler { +class GFX_EXPORT KMeanImageSampler { public: virtual int GetSample(int width, int height) = 0; @@ -35,7 +35,7 @@ class UI_EXPORT KMeanImageSampler { }; // This sampler will pick pixels from an evenly spaced grid. -class UI_EXPORT GridSampler : public KMeanImageSampler { +class GFX_EXPORT GridSampler : public KMeanImageSampler { public: GridSampler(); virtual ~GridSampler(); @@ -49,8 +49,8 @@ class UI_EXPORT GridSampler : public KMeanImageSampler { // Returns the color in an ARGB |image| that is closest in RGB-space to the // provided |color|. Exported for testing. -UI_EXPORT SkColor FindClosestColor(const uint8_t* image, int width, int height, - SkColor color); +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 @@ -89,7 +89,7 @@ UI_EXPORT SkColor FindClosestColor(const uint8_t* image, int width, int height, // // Note: Switching to HSV space did not improve the results of this algorithm // for typical favicon images. -UI_EXPORT SkColor CalculateKMeanColorOfPNG( +GFX_EXPORT SkColor CalculateKMeanColorOfPNG( scoped_refptr<base::RefCountedMemory> png, uint32_t darkness_limit, uint32_t brightness_limit, @@ -97,10 +97,10 @@ UI_EXPORT SkColor CalculateKMeanColorOfPNG( // Computes a dominant color for an SkBitmap using the above algorithm and // reasonable defaults for |darkness_limit|, |brightness_limit| and |sampler|. -UI_EXPORT SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap); +GFX_EXPORT SkColor CalculateKMeanColorOfBitmap(const SkBitmap& bitmap); // Compute color covariance matrix for the input bitmap. -UI_EXPORT gfx::Matrix3F ComputeColorCovariance(const SkBitmap& bitmap); +GFX_EXPORT gfx::Matrix3F ComputeColorCovariance(const SkBitmap& bitmap); // Apply a color reduction transform defined by |color_transform| vector to // |source_bitmap|. The result is put into |target_bitmap|, which is expected @@ -108,7 +108,7 @@ UI_EXPORT gfx::Matrix3F ComputeColorCovariance(const SkBitmap& bitmap); // If |fit_to_range|, result is transfored linearly to fit 0-0xFF range. // Otherwise, data is clipped. // Returns true if the target has been computed. -UI_EXPORT bool ApplyColorReduction(const SkBitmap& source_bitmap, +GFX_EXPORT bool ApplyColorReduction(const SkBitmap& source_bitmap, const gfx::Vector3dF& color_transform, bool fit_to_range, SkBitmap* target_bitmap); @@ -119,7 +119,7 @@ UI_EXPORT bool ApplyColorReduction(const SkBitmap& source_bitmap, // Returns true if the conversion succeeded. Note that there might be legitimate // reasons for the process to fail even if all input was correct. This is a // condition the caller must be able to handle. -UI_EXPORT bool ComputePrincipalComponentImage(const SkBitmap& source_bitmap, +GFX_EXPORT bool ComputePrincipalComponentImage(const SkBitmap& source_bitmap, SkBitmap* target_bitmap); } // namespace color_utils diff --git a/chromium/ui/gfx/color_analysis_unittest.cc b/chromium/ui/gfx/color_analysis_unittest.cc index c76681c2ac9..7757eb959ba 100644 --- a/chromium/ui/gfx/color_analysis_unittest.cc +++ b/chromium/ui/gfx/color_analysis_unittest.cc @@ -295,7 +295,7 @@ TEST_F(ColorAnalysisTest, ComputeColorCovarianceTrivial) { } TEST_F(ColorAnalysisTest, ComputeColorCovarianceWithCanvas) { - gfx::Canvas canvas(gfx::Size(250, 200), ui::SCALE_FACTOR_100P, true); + gfx::Canvas canvas(gfx::Size(250, 200), 1.0f, true); // The image consists of vertical stripes, with color bands set to 100 // in overlapping stripes 150 pixels wide. canvas.FillRect(gfx::Rect(0, 0, 50, 200), SkColorSetRGB(100, 0, 0)); @@ -364,7 +364,7 @@ TEST_F(ColorAnalysisTest, ApplyColorReductionSingleColor) { TEST_F(ColorAnalysisTest, ApplyColorReductionBlackAndWhite) { // Check with images with multiple colors. This is really different only when // the result is scaled. - gfx::Canvas canvas(gfx::Size(300, 200), ui::SCALE_FACTOR_100P, true); + gfx::Canvas canvas(gfx::Size(300, 200), 1.0f, true); // The image consists of vertical non-overlapping stripes 150 pixels wide. canvas.FillRect(gfx::Rect(0, 0, 150, 200), SkColorSetRGB(0, 0, 0)); @@ -404,7 +404,7 @@ TEST_F(ColorAnalysisTest, ApplyColorReductionBlackAndWhite) { TEST_F(ColorAnalysisTest, ApplyColorReductionMultiColor) { // Check with images with multiple colors. This is really different only when // the result is scaled. - gfx::Canvas canvas(gfx::Size(300, 200), ui::SCALE_FACTOR_100P, true); + gfx::Canvas canvas(gfx::Size(300, 200), 1.0f, true); // The image consists of vertical non-overlapping stripes 100 pixels wide. canvas.FillRect(gfx::Rect(0, 0, 100, 200), SkColorSetRGB(100, 0, 0)); @@ -452,7 +452,7 @@ TEST_F(ColorAnalysisTest, ComputePrincipalComponentImageNotComputable) { } TEST_F(ColorAnalysisTest, ComputePrincipalComponentImage) { - gfx::Canvas canvas(gfx::Size(300, 200), ui::SCALE_FACTOR_100P, true); + gfx::Canvas canvas(gfx::Size(300, 200), 1.0f, true); // The image consists of vertical non-overlapping stripes 100 pixels wide. canvas.FillRect(gfx::Rect(0, 0, 100, 200), SkColorSetRGB(10, 10, 10)); diff --git a/chromium/ui/gfx/color_profile.h b/chromium/ui/gfx/color_profile.h index 3a3f5b2ce04..20a02bf169f 100644 --- a/chromium/ui/gfx/color_profile.h +++ b/chromium/ui/gfx/color_profile.h @@ -16,7 +16,7 @@ namespace gfx { static const size_t kMinProfileLength = 128; static const size_t kMaxProfileLength = 4 * 1024 * 1024; -class UI_EXPORT ColorProfile { +class GFX_EXPORT ColorProfile { public: // On Windows, this reads a file from disk so it shouldn't be run on the UI // or IO thread. @@ -32,7 +32,7 @@ class UI_EXPORT ColorProfile { }; // Loads the monitor color space if available. -UI_EXPORT void GetColorProfile(std::vector<char>* profile); +GFX_EXPORT void GetColorProfile(std::vector<char>* profile); } // namespace gfx diff --git a/chromium/ui/gfx/color_utils.h b/chromium/ui/gfx/color_utils.h index 440e3825c31..6dd6300aa3b 100644 --- a/chromium/ui/gfx/color_utils.h +++ b/chromium/ui/gfx/color_utils.h @@ -20,14 +20,14 @@ struct HSL { double l; }; -UI_EXPORT unsigned char GetLuminanceForColor(SkColor color); +GFX_EXPORT unsigned char GetLuminanceForColor(SkColor color); // Calculated according to http://www.w3.org/TR/WCAG20/#relativeluminancedef -UI_EXPORT double RelativeLuminance(SkColor color); +GFX_EXPORT double RelativeLuminance(SkColor color); // Note: these transformations assume sRGB as the source color space -UI_EXPORT void SkColorToHSL(SkColor c, HSL* hsl); -UI_EXPORT SkColor HSLToSkColor(const HSL& hsl, SkAlpha alpha); +GFX_EXPORT void SkColorToHSL(SkColor c, HSL* hsl); +GFX_EXPORT SkColor HSLToSkColor(const HSL& hsl, SkAlpha alpha); // 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: @@ -43,29 +43,23 @@ UI_EXPORT SkColor HSLToSkColor(const HSL& hsl, SkAlpha alpha); // 0 = remove all lightness (make all pixels black). // 0.5 = leave unchanged. // 1 = full lightness (make all pixels white). -UI_EXPORT SkColor HSLShift(SkColor color, const HSL& shift); - -// Determine if a given alpha value is nearly completely transparent. -bool IsColorCloseToTransparent(SkAlpha alpha); - -// Determine if a color is near grey. -bool IsColorCloseToGrey(int r, int g, int b); +GFX_EXPORT SkColor HSLShift(SkColor color, const HSL& shift); // Builds a histogram based on the Y' of the Y'UV representation of // this image. -UI_EXPORT void BuildLumaHistogram(const SkBitmap& bitmap, int histogram[256]); +GFX_EXPORT void BuildLumaHistogram(const SkBitmap& bitmap, int histogram[256]); // Returns a blend of the supplied colors, ranging from |background| (for // |alpha| == 0) to |foreground| (for |alpha| == 255). The alpha channels of // the supplied colors are also taken into account, so the returned color may // be partially transparent. -UI_EXPORT SkColor AlphaBlend(SkColor foreground, SkColor background, - SkAlpha alpha); +GFX_EXPORT SkColor AlphaBlend(SkColor foreground, SkColor background, + SkAlpha alpha); // Makes a dark color lighter or a light color darker by blending |color| with // white or black depending on its current luminance. |alpha| controls the // amount of white or black that will be alpha-blended into |color|. -UI_EXPORT SkColor BlendTowardOppositeLuminance(SkColor color, SkAlpha alpha); +GFX_EXPORT SkColor BlendTowardOppositeLuminance(SkColor color, SkAlpha alpha); // Given an opaque foreground and background color, try to return a foreground // color that is "readable" over the background color by luma-inverting the @@ -76,13 +70,13 @@ UI_EXPORT SkColor BlendTowardOppositeLuminance(SkColor color, SkAlpha alpha); // // NOTE: This won't do anything but waste time if the supplied foreground color // has a luma value close to the midpoint (0.5 in the HSL representation). -UI_EXPORT SkColor GetReadableColor(SkColor foreground, SkColor background); +GFX_EXPORT SkColor GetReadableColor(SkColor foreground, SkColor background); // Invert a color. -UI_EXPORT SkColor InvertColor(SkColor color); +GFX_EXPORT SkColor InvertColor(SkColor color); // Gets a Windows system color as a SkColor -UI_EXPORT SkColor GetSysSkColor(int which); +GFX_EXPORT SkColor GetSysSkColor(int which); } // namespace color_utils diff --git a/chromium/ui/gfx/display.cc b/chromium/ui/gfx/display.cc index ee650d8964f..024b1f9aaa6 100644 --- a/chromium/ui/gfx/display.cc +++ b/chromium/ui/gfx/display.cc @@ -57,13 +57,15 @@ bool Display::HasForceDeviceScaleFactor() { Display::Display() : id_(kInvalidDisplayID), device_scale_factor_(GetForcedDeviceScaleFactor()), - rotation_(ROTATE_0) { + rotation_(ROTATE_0), + touch_support_(TOUCH_SUPPORT_UNKNOWN) { } Display::Display(int64 id) : id_(id), device_scale_factor_(GetForcedDeviceScaleFactor()), - rotation_(ROTATE_0) { + rotation_(ROTATE_0), + touch_support_(TOUCH_SUPPORT_UNKNOWN) { } Display::Display(int64 id, const gfx::Rect& bounds) @@ -71,7 +73,8 @@ Display::Display(int64 id, const gfx::Rect& bounds) bounds_(bounds), work_area_(bounds), device_scale_factor_(GetForcedDeviceScaleFactor()), - rotation_(ROTATE_0) { + rotation_(ROTATE_0), + touch_support_(TOUCH_SUPPORT_UNKNOWN) { #if defined(USE_AURA) SetScaleAndBounds(device_scale_factor_, bounds); #endif diff --git a/chromium/ui/gfx/display.h b/chromium/ui/gfx/display.h index 17cedfe38fe..eb35a5f5c6f 100644 --- a/chromium/ui/gfx/display.h +++ b/chromium/ui/gfx/display.h @@ -20,7 +20,7 @@ namespace gfx { // system. For platforms that support DIP (density independent pixel), // |bounds()| and |work_area| will return values in DIP coordinate // system, not in backing pixels. -class UI_EXPORT Display { +class GFX_EXPORT Display { public: // Screen Rotation in clock-wise degrees. enum Rotation { @@ -30,6 +30,13 @@ class UI_EXPORT Display { ROTATE_270, }; + // Touch support for the display. + enum TouchSupport { + TOUCH_SUPPORT_UNKNOWN, + TOUCH_SUPPORT_AVAILABLE, + TOUCH_SUPPORT_UNAVAILABLE, + }; + // Creates a display with kInvalidDisplayID as default. Display(); explicit Display(int64 id); @@ -67,6 +74,9 @@ class UI_EXPORT Display { Rotation rotation() const { return rotation_; } void set_rotation(Rotation rotation) { rotation_ = rotation; } + TouchSupport touch_support() const { return touch_support_; } + void set_touch_support(TouchSupport support) { touch_support_ = support; } + // Utility functions that just return the size of display and // work area. const Size& size() const { return bounds_.size(); } @@ -113,6 +123,7 @@ class UI_EXPORT Display { Rect work_area_; float device_scale_factor_; Rotation rotation_; + TouchSupport touch_support_; }; } // namespace gfx diff --git a/chromium/ui/gfx/display_observer.h b/chromium/ui/gfx/display_observer.h index 1e7cd8cb899..ca97247f9ed 100644 --- a/chromium/ui/gfx/display_observer.h +++ b/chromium/ui/gfx/display_observer.h @@ -13,7 +13,7 @@ class Display; // Observers for display configuration changes. // TODO(oshima): consolidate |WorkAreaWatcherObserver| and // |DisplaySettingsProvier|. crbug.com/122863. -class UI_EXPORT DisplayObserver { +class GFX_EXPORT DisplayObserver { public: // Called when the |display|'s bound has changed. virtual void OnDisplayBoundsChanged(const Display& display) = 0; diff --git a/chromium/ui/gfx/favicon_size.h b/chromium/ui/gfx/favicon_size.h index ecab851dc1a..ad51a9bdb00 100644 --- a/chromium/ui/gfx/favicon_size.h +++ b/chromium/ui/gfx/favicon_size.h @@ -10,12 +10,12 @@ namespace gfx { // Size (along each axis) of the favicon. -UI_EXPORT extern const int kFaviconSize; +GFX_EXPORT extern const int kFaviconSize; // If the width or height is bigger than the favicon size, a new width/height // is calculated and returned in width/height that maintains the aspect // ratio of the supplied values. -UI_EXPORT void CalculateFaviconTargetSize(int* width, int* height); +GFX_EXPORT void CalculateFaviconTargetSize(int* width, int* height); } // namespace gfx diff --git a/chromium/ui/gfx/font.cc b/chromium/ui/gfx/font.cc index aa4638c7efc..9eea73b608a 100644 --- a/chromium/ui/gfx/font.cc +++ b/chromium/ui/gfx/font.cc @@ -54,6 +54,10 @@ int Font::GetBaseline() const { return platform_font_->GetBaseline(); } +int Font::GetCapHeight() const { + return platform_font_->GetCapHeight(); +} + int Font::GetAverageCharacterWidth() const { return platform_font_->GetAverageCharacterWidth(); } @@ -74,6 +78,10 @@ std::string Font::GetFontName() const { return platform_font_->GetFontName(); } +std::string Font::GetActualFontNameForTesting() const { + return platform_font_->GetActualFontNameForTesting(); +} + int Font::GetFontSize() const { return platform_font_->GetFontSize(); } diff --git a/chromium/ui/gfx/font.h b/chromium/ui/gfx/font.h index dfbf410f30c..963dde70ffe 100644 --- a/chromium/ui/gfx/font.h +++ b/chromium/ui/gfx/font.h @@ -18,7 +18,16 @@ class PlatformFont; // Font provides a wrapper around an underlying font. Copy and assignment // operators are explicitly allowed, and cheap. -class UI_EXPORT Font { +// +// Figure of font metrics: +// +--------+-------------------+------------------+ +// | | | internal leading | +// | | ascent (baseline) +------------------+ +// | height | | cap height | +// | |-------------------+------------------+ +// | | descent (height - baseline) | +// +--------+--------------------------------------+ +class GFX_EXPORT Font { public: // The following constants indicate the font style. enum FontStyle { @@ -69,6 +78,9 @@ class UI_EXPORT Font { // Returns the baseline, or ascent, of the font. int GetBaseline() const; + // Returns the cap height of the font. + int GetCapHeight() const; + // Returns the average character width for the font. int GetAverageCharacterWidth() const; @@ -84,9 +96,12 @@ class UI_EXPORT Font { // Returns the style of the font. int GetStyle() const; - // Returns the font name in UTF-8. + // Returns the specified font name in UTF-8. std::string GetFontName() const; + // Returns the actually used font name in UTF-8. + std::string GetActualFontNameForTesting() const; + // Returns the font size in pixels. int GetFontSize() const; diff --git a/chromium/ui/gfx/font_fallback_win.h b/chromium/ui/gfx/font_fallback_win.h index 7e206da4f43..ee675714e7f 100644 --- a/chromium/ui/gfx/font_fallback_win.h +++ b/chromium/ui/gfx/font_fallback_win.h @@ -20,20 +20,20 @@ namespace internal { // // Sets |filename| and |font_name| respectively. If a field is not present // or could not be parsed, the corresponding parameter will be cleared. -void UI_EXPORT ParseFontLinkEntry(const std::string& entry, +void GFX_EXPORT ParseFontLinkEntry(const std::string& entry, std::string* filename, std::string* font_name); // Parses a font |family| in the format "FamilyFoo & FamilyBar (TrueType)". // Splits by '&' and strips off the trailing parenthesized expression. -void UI_EXPORT ParseFontFamilyString(const std::string& family, +void GFX_EXPORT ParseFontFamilyString(const std::string& family, std::vector<std::string>* font_names); } // namespace internal // Iterator over linked fallback fonts for a given font. The linked font chain // comes from the Windows registry, but gets cached between uses. -class UI_EXPORT LinkedFontsIterator { +class GFX_EXPORT LinkedFontsIterator { public: // Instantiates the iterator over the linked font chain for |font|. The first // item will be |font| itself. diff --git a/chromium/ui/gfx/font_list.cc b/chromium/ui/gfx/font_list.cc index e01483a7cc1..3b1ab9bcd1f 100644 --- a/chromium/ui/gfx/font_list.cc +++ b/chromium/ui/gfx/font_list.cc @@ -6,6 +6,7 @@ #include <algorithm> +#include "base/lazy_instance.h" #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" @@ -13,6 +14,10 @@ namespace { +// Font description of the default font set. +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, @@ -75,7 +80,14 @@ FontList::FontList() common_baseline_(-1), font_style_(-1), font_size_(-1) { - fonts_.push_back(Font()); + // 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."; + + font_description_string_ = g_default_font_description.Get(); + if (font_description_string_.empty()) + fonts_.push_back(Font()); } FontList::FontList(const std::string& font_description_string) @@ -130,6 +142,16 @@ FontList::FontList(const Font& font) FontList::~FontList() { } +// static +void FontList::SetDefaultFontDescription(const std::string& font_description) { + // The description string must end with "px" for size in pixel, or must be + // the empty string, which specifies to use a single default font. + DCHECK(font_description.empty() || + EndsWith(font_description, "px", true)); + + g_default_font_description.Get() = font_description; +} + FontList FontList::DeriveFontList(int font_style) const { return DeriveFontListWithSizeDeltaAndStyle(0, font_style); } @@ -177,6 +199,11 @@ int FontList::GetBaseline() const { return common_baseline_; } +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 diff --git a/chromium/ui/gfx/font_list.h b/chromium/ui/gfx/font_list.h index ae96251cce8..e37fd625a23 100644 --- a/chromium/ui/gfx/font_list.h +++ b/chromium/ui/gfx/font_list.h @@ -32,7 +32,7 @@ namespace gfx { // // FontList allows operator= since FontList is a data member type in RenderText, // and operator= is used in RenderText::SetFontList(). -class UI_EXPORT FontList { +class GFX_EXPORT FontList { public: // Creates a font list with a Font with default name and style. FontList(); @@ -55,6 +55,16 @@ class UI_EXPORT FontList { ~FontList(); + // Sets the description string for default FontList construction. If it's + // empty, FontList will initialize using the default Font constructor. + // + // The client code must call this function before any call of the default + // constructor. This should be done on the UI thread. + // + // ui::ResourceBundle may call this function more than once when UI language + // 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; @@ -81,6 +91,10 @@ class UI_EXPORT FontList { // 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 number of horizontal pixels needed to display |text|. int GetStringWidth(const base::string16& text) const; diff --git a/chromium/ui/gfx/font_list_unittest.cc b/chromium/ui/gfx/font_list_unittest.cc index a62a13db469..6cbb41fbecd 100644 --- a/chromium/ui/gfx/font_list_unittest.cc +++ b/chromium/ui/gfx/font_list_unittest.cc @@ -9,6 +9,7 @@ #include <vector> #include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -292,6 +293,7 @@ TEST(FontListTest, Fonts_DeriveFontListWithSizeDeltaAndStyle) { 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); + ASSERT_EQ("arial", StringToLowerASCII(font1.GetActualFontNameForTesting())); FontList font_list1("Arial, 16px"); EXPECT_EQ(font1.GetHeight(), font_list1.GetHeight()); EXPECT_EQ(font1.GetBaseline(), font_list1.GetBaseline()); @@ -299,6 +301,7 @@ TEST(FontListTest, Fonts_GetHeight_GetBaseline) { // If there are two different fonts, the font list returns the max value // for ascent and descent. Font font2("Symbol", 16); + ASSERT_EQ("symbol", StringToLowerASCII(font2.GetActualFontNameForTesting())); EXPECT_NE(font1.GetBaseline(), font2.GetBaseline()); EXPECT_NE(font1.GetHeight() - font1.GetBaseline(), font2.GetHeight() - font2.GetBaseline()); diff --git a/chromium/ui/gfx/font_render_params_linux.h b/chromium/ui/gfx/font_render_params_linux.h index 9ba6ca971b2..ac8323ceade 100644 --- a/chromium/ui/gfx/font_render_params_linux.h +++ b/chromium/ui/gfx/font_render_params_linux.h @@ -10,7 +10,7 @@ namespace gfx { // A collection of parameters describing how text should be rendered on Linux. -struct UI_EXPORT FontRenderParams { +struct GFX_EXPORT FontRenderParams { // No constructor to avoid static initialization. // Level of hinting to be applied. @@ -54,16 +54,16 @@ struct UI_EXPORT FontRenderParams { }; // Returns the system's default parameters for font rendering. -UI_EXPORT const FontRenderParams& GetDefaultFontRenderParams(); +GFX_EXPORT const FontRenderParams& GetDefaultFontRenderParams(); // Returns the system's default parameters for WebKit font rendering. -UI_EXPORT const FontRenderParams& GetDefaultWebKitFontRenderParams(); +GFX_EXPORT const FontRenderParams& GetDefaultWebKitFontRenderParams(); // Returns the system's default parameters for WebKit subpixel positioning. // Subpixel positioning is special since neither GTK nor FontConfig currently // track it as a preference. // See https://bugs.freedesktop.org/show_bug.cgi?id=50736 -UI_EXPORT bool GetDefaultWebkitSubpixelPositioning(); +GFX_EXPORT bool GetDefaultWebkitSubpixelPositioning(); } // namespace gfx diff --git a/chromium/ui/gfx/font_unittest.cc b/chromium/ui/gfx/font_unittest.cc index 6b5cb798657..2fdaab872f4 100644 --- a/chromium/ui/gfx/font_unittest.cc +++ b/chromium/ui/gfx/font_unittest.cc @@ -5,10 +5,11 @@ #include "ui/gfx/font.h" #include "base/strings/string16.h" +#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) +#if defined(OS_LINUX) && !defined(USE_OZONE) #include <pango/pango.h> #elif defined(OS_WIN) #include "ui/gfx/platform_font_win.h" @@ -22,7 +23,7 @@ class FontTest : public testing::Test { // Fulfills the memory management contract as outlined by the comment at // gfx::Font::GetNativeFont(). void FreeIfNecessary(NativeFont font) { -#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID) +#if defined(OS_LINUX) && !defined(USE_OZONE) pango_font_description_free(font); #endif } @@ -59,10 +60,11 @@ int ScopedMinimumFontSizeCallback::minimum_size_ = 0; TEST_F(FontTest, LoadArial) { Font cf("Arial", 16); NativeFont native = cf.GetNativeFont(); - ASSERT_TRUE(native); - ASSERT_EQ(cf.GetStyle(), Font::NORMAL); - ASSERT_EQ(cf.GetFontSize(), 16); - ASSERT_EQ(cf.GetFontName(), "Arial"); + EXPECT_TRUE(native); + EXPECT_EQ(cf.GetStyle(), Font::NORMAL); + EXPECT_EQ(cf.GetFontSize(), 16); + EXPECT_EQ(cf.GetFontName(), "Arial"); + EXPECT_EQ("arial", StringToLowerASCII(cf.GetActualFontNameForTesting())); FreeIfNecessary(native); } @@ -70,48 +72,76 @@ TEST_F(FontTest, LoadArialBold) { Font cf("Arial", 16); Font bold(cf.DeriveFont(0, Font::BOLD)); NativeFont native = bold.GetNativeFont(); - ASSERT_TRUE(native); - ASSERT_EQ(bold.GetStyle(), Font::BOLD); + EXPECT_TRUE(native); + EXPECT_EQ(bold.GetStyle(), Font::BOLD); + EXPECT_EQ("arial", StringToLowerASCII(cf.GetActualFontNameForTesting())); FreeIfNecessary(native); } TEST_F(FontTest, Ascent) { Font cf("Arial", 16); - ASSERT_GT(cf.GetBaseline(), 2); - ASSERT_LE(cf.GetBaseline(), 22); + EXPECT_GT(cf.GetBaseline(), 2); + EXPECT_LE(cf.GetBaseline(), 22); } TEST_F(FontTest, Height) { Font cf("Arial", 16); - ASSERT_GE(cf.GetHeight(), 16); + EXPECT_GE(cf.GetHeight(), 16); // TODO(akalin): Figure out why height is so large on Linux. - ASSERT_LE(cf.GetHeight(), 26); + EXPECT_LE(cf.GetHeight(), 26); +} + +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) { Font cf("Arial", 16); - ASSERT_EQ(cf.GetExpectedTextWidth(0), 0); - ASSERT_GT(cf.GetExpectedTextWidth(1), cf.GetExpectedTextWidth(0)); - ASSERT_GT(cf.GetExpectedTextWidth(2), cf.GetExpectedTextWidth(1)); - ASSERT_GT(cf.GetExpectedTextWidth(3), cf.GetExpectedTextWidth(2)); + EXPECT_EQ(cf.GetExpectedTextWidth(0), 0); + EXPECT_GT(cf.GetExpectedTextWidth(1), cf.GetExpectedTextWidth(0)); + EXPECT_GT(cf.GetExpectedTextWidth(2), cf.GetExpectedTextWidth(1)); + EXPECT_GT(cf.GetExpectedTextWidth(3), cf.GetExpectedTextWidth(2)); } TEST_F(FontTest, AvgCharWidth) { Font cf("Arial", 16); - ASSERT_GT(cf.GetAverageCharacterWidth(), 0); + EXPECT_GT(cf.GetAverageCharacterWidth(), 0); } TEST_F(FontTest, Widths) { Font cf("Arial", 16); - ASSERT_EQ(cf.GetStringWidth(base::string16()), 0); - ASSERT_GT(cf.GetStringWidth(ASCIIToUTF16("a")), + EXPECT_EQ(cf.GetStringWidth(base::string16()), 0); + EXPECT_GT(cf.GetStringWidth(ASCIIToUTF16("a")), cf.GetStringWidth(base::string16())); - ASSERT_GT(cf.GetStringWidth(ASCIIToUTF16("ab")), + EXPECT_GT(cf.GetStringWidth(ASCIIToUTF16("ab")), cf.GetStringWidth(ASCIIToUTF16("a"))); - ASSERT_GT(cf.GetStringWidth(ASCIIToUTF16("abc")), + 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 +TEST_F(FontTest, GetActualFontNameForTesting) { + Font arial("Arial", 16); + EXPECT_EQ("arial", StringToLowerASCII(arial.GetActualFontNameForTesting())); + Font symbol("Symbol", 16); + EXPECT_EQ("symbol", StringToLowerASCII(symbol.GetActualFontNameForTesting())); + + const char* const invalid_font_name = "no_such_font_name"; + Font fallback_font(invalid_font_name, 16); + EXPECT_NE(invalid_font_name, + StringToLowerASCII(fallback_font.GetActualFontNameForTesting())); +} +#endif + #if defined(OS_WIN) TEST_F(FontTest, DeriveFontResizesIfSizeTooSmall) { Font cf("Arial", 8); diff --git a/chromium/ui/gfx/frame_time.h b/chromium/ui/gfx/frame_time.h new file mode 100644 index 00000000000..5cc65f5f4a8 --- /dev/null +++ b/chromium/ui/gfx/frame_time.h @@ -0,0 +1,40 @@ +// 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_FRAME_TIME_H +#define UI_GFX_FRAME_TIME_H + +#include "base/time/time.h" +#include "base/logging.h" + +namespace gfx { + +// FrameTime::Now() should be used to get timestamps with a timebase that +// is consistent across the graphics stack. +class FrameTime { + public: + static base::TimeTicks Now() { + if (TimestampsAreHighRes()) + return base::TimeTicks::HighResNow(); + return base::TimeTicks::Now(); + } + +#if defined(OS_WIN) + static base::TimeTicks FromQPCValue(LONGLONG qpc_value) { + DCHECK(TimestampsAreHighRes()); + return base::TimeTicks::FromQPCValue(qpc_value); + } +#endif + + static bool TimestampsAreHighRes() { + // This should really return base::TimeTicks::IsHighResNowFastAndReliable(); + // Returning false makes sure we are only using low-res timestamps until we + // use FrameTime everywhere we need to. See crbug.com/315334 + return false; + } +}; + +} + +#endif // UI_GFX_FRAME_TIME_H diff --git a/chromium/ui/gfx/gdi_util.h b/chromium/ui/gfx/gdi_util.h index 53b6e91a897..d8563b69966 100644 --- a/chromium/ui/gfx/gdi_util.h +++ b/chromium/ui/gfx/gdi_util.h @@ -15,7 +15,8 @@ namespace gfx { // Creates a BITMAPINFOHEADER structure given the bitmap's size. -UI_EXPORT void CreateBitmapHeader(int width, int height, BITMAPINFOHEADER* hdr); +GFX_EXPORT void CreateBitmapHeader(int width, int height, + BITMAPINFOHEADER* hdr); // Creates a BITMAPINFOHEADER structure given the bitmap's size and // color depth in bits per pixel. @@ -25,28 +26,29 @@ void CreateBitmapHeaderWithColorDepth(int width, int height, int color_depth, // Creates a BITMAPV4HEADER structure given the bitmap's size. You probably // only need to use BMP V4 if you need transparency (alpha channel). This // function sets the AlphaMask to 0xff000000. -UI_EXPORT void CreateBitmapV4Header(int width, int height, BITMAPV4HEADER* hdr); +GFX_EXPORT void CreateBitmapV4Header(int width, int height, + BITMAPV4HEADER* hdr); // Creates a monochrome bitmap header. void CreateMonochromeBitmapHeader(int width, int height, BITMAPINFOHEADER* hdr); // Modify the given hrgn by subtracting the given rectangles. -UI_EXPORT void SubtractRectanglesFromRegion( +GFX_EXPORT void SubtractRectanglesFromRegion( HRGN hrgn, const std::vector<gfx::Rect>& cutouts); -UI_EXPORT HRGN ConvertPathToHRGN(const gfx::Path& path); +GFX_EXPORT HRGN ConvertPathToHRGN(const gfx::Path& path); // Calculate scale to fit an entire page on DC. -UI_EXPORT double CalculatePageScale(HDC dc, int page_width, int page_height); +GFX_EXPORT double CalculatePageScale(HDC dc, int page_width, int page_height); // Apply scaling to the DC. -UI_EXPORT bool ScaleDC(HDC dc, double scale_factor); +GFX_EXPORT bool ScaleDC(HDC dc, double scale_factor); -UI_EXPORT void StretchDIBits(HDC hdc, - int dest_x, int dest_y, int dest_w, int dest_h, - int src_x, int src_y, int src_w, int src_h, - void* pixels, const BITMAPINFO* bitmap_info); +GFX_EXPORT void StretchDIBits(HDC hdc, + int dest_x, int dest_y, int dest_w, int dest_h, + int src_x, int src_y, int src_w, int src_h, + void* pixels, const BITMAPINFO* bitmap_info); } // namespace gfx diff --git a/chromium/ui/gfx/gfx.gyp b/chromium/ui/gfx/gfx.gyp new file mode 100644 index 00000000000..5fb17d52ee6 --- /dev/null +++ b/chromium/ui/gfx/gfx.gyp @@ -0,0 +1,440 @@ +# 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. + +{ + 'variables': { + 'chromium_code': 1, + }, + 'targets': [ + { + 'target_name': 'gfx', + 'type': '<(component)', + 'dependencies': [ + '<(DEPTH)/base/base.gyp:base', + '<(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/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', + ], + # text_elider.h includes ICU headers. + 'export_dependent_settings': [ + '<(DEPTH)/skia/skia.gyp:skia', + '<(DEPTH)/third_party/icu/icu.gyp:icui18n', + '<(DEPTH)/third_party/icu/icu.gyp:icuuc', + ], + 'defines': [ + 'GFX_IMPLEMENTATION', + ], + '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/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', + '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', + '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.cc', + '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', + 'frame_time.h', + 'font.cc', + 'font.h', + 'font_fallback_win.cc', + 'font_fallback_win.h', + 'font_list.cc', + 'font_list.h', + 'font_render_params_android.cc', + 'font_render_params_linux.cc', + 'font_render_params_linux.h', + 'font_smoothing_win.cc', + 'font_smoothing_win.h', + 'gfx_export.h', + 'gfx_paths.cc', + 'gfx_paths.h', + 'gpu_memory_buffer.cc', + 'gpu_memory_buffer.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', + 'insets.cc', + 'insets.h', + 'insets_base.h', + 'insets_f.cc', + 'insets_f.h', + 'interpolated_transform.cc', + 'interpolated_transform.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', + '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', + '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_ozone.cc', + 'platform_font_pango.cc', + '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_mac.cc', + 'render_text_mac.h', + 'render_text_ozone.cc', + 'render_text_pango.cc', + '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', + '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_gtk.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', + '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', + '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', + 'text_utils_skia.cc', + 'transform.cc', + 'transform.h', + 'transform_util.cc', + 'transform_util.h', + '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', + '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', + 'x/x11_atom_cache.cc', + 'x/x11_atom_cache.h', + 'x/x11_types.cc', + 'x/x11_types.h', + ], + 'conditions': [ + ['OS=="ios"', { + # iOS only uses a subset of UI. + 'sources/': [ + ['exclude', '^codec/jpeg_codec\\.cc$'], + ], + }, { + 'dependencies': [ + '<(libjpeg_gyp_path):libjpeg', + ], + }], + # TODO(asvitkine): Switch all platforms to use canvas_skia.cc. + # http://crbug.com/105550 + ['use_canvas_skia==1', { + 'sources!': [ + 'canvas_android.cc', + ], + }, { # use_canvas_skia!=1 + 'sources!': [ + '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', + 'gdi_util.h', + 'icon_util.cc', + 'icon_util.h', + ], + # TODO(jschuh): C4267: http://crbug.com/167187 size_t -> int + # C4324 is structure was padded due to __declspec(align()), which is + # uninteresting. + 'msvs_disabled_warnings': [ 4267, 4324 ], + }], + ['OS=="android"', { + 'sources!': [ + 'animation/throb_animation.cc', + 'display_observer.cc', + 'path.cc', + 'selection_model.cc', + ], + 'dependencies': [ + 'gfx_jni_headers', + ], + 'link_settings': { + 'libraries': [ + '-landroid', + '-ljnigraphics', + ], + }, + }], + ['OS=="android" and android_webview_build==0', { + 'dependencies': [ + '<(DEPTH)/base/base.gyp:base_java', + ], + }], + ['OS=="android" or OS=="ios"', { + 'sources!': [ + 'render_text.cc', + 'render_text.h', + 'text_utils_skia.cc', + ], + }], + ['use_pango==1', { + 'dependencies': [ + '<(DEPTH)/build/linux/system.gyp:pangocairo', + ], + 'sources!': [ + 'platform_font_ozone.cc', + 'render_text_ozone.cc', + ], + }], + ['ozone_platform_dri==1', { + 'dependencies': [ + '<(DEPTH)/build/linux/system.gyp:dridrm', + ], + }], + ], + 'target_conditions': [ + # Need 'target_conditions' to override default filename_rules to include + # the file on iOS. + ['OS == "ios"', { + 'sources/': [ + ['include', '^scoped_cg_context_save_gstate_mac\\.h$'], + ], + }], + ], + } + ], + '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', + ], + 'variables': { + 'jni_gen_package': 'ui/gfx', + 'jni_generator_ptr_type': 'long' + }, + 'includes': [ '../../build/jni_generator.gypi' ], + }, + ], + }], + ], +} diff --git a/chromium/ui/gfx/gfx_export.h b/chromium/ui/gfx/gfx_export.h index f610d98d82d..20c8bb1681d 100644 --- a/chromium/ui/gfx/gfx_export.h +++ b/chromium/ui/gfx/gfx_export.h @@ -5,21 +5,17 @@ #ifndef UI_GFX_GFX_EXPORT_H_ #define UI_GFX_GFX_EXPORT_H_ -// TODO(beng): remove include once gfx dependencies have been corrected. - -#include "ui/base/ui_export.h" - #if defined(COMPONENT_BUILD) #if defined(WIN32) -#if defined(UI_IMPLEMENTATION) +#if defined(GFX_IMPLEMENTATION) #define GFX_EXPORT __declspec(dllexport) #else #define GFX_EXPORT __declspec(dllimport) -#endif // defined(UI_IMPLEMENTATION) +#endif // defined(GFX_IMPLEMENTATION) #else // defined(WIN32) -#if defined(UI_IMPLEMENTATION) +#if defined(GFX_IMPLEMENTATION) #define GFX_EXPORT __attribute__((visibility("default"))) #else #define GFX_EXPORT diff --git a/chromium/ui/gfx/gfx_paths.h b/chromium/ui/gfx/gfx_paths.h index d5eec96fd74..7a779edbc92 100644 --- a/chromium/ui/gfx/gfx_paths.h +++ b/chromium/ui/gfx/gfx_paths.h @@ -22,7 +22,7 @@ enum { }; // Call once to register the provider for the path keys defined above. -UI_EXPORT void RegisterPathProvider(); +GFX_EXPORT void RegisterPathProvider(); } // namespace gfx diff --git a/chromium/ui/gfx/gpu_memory_buffer.h b/chromium/ui/gfx/gpu_memory_buffer.h index c600527f022..4a7b142d175 100644 --- a/chromium/ui/gfx/gpu_memory_buffer.h +++ b/chromium/ui/gfx/gpu_memory_buffer.h @@ -18,7 +18,8 @@ namespace gfx { enum GpuMemoryBufferType { EMPTY_BUFFER, SHARED_MEMORY_BUFFER, - EGL_CLIENT_BUFFER + EGL_CLIENT_BUFFER, + IO_SURFACE_BUFFER }; struct GpuMemoryBufferHandle { @@ -28,6 +29,9 @@ struct GpuMemoryBufferHandle { #if defined(OS_ANDROID) , native_buffer(NULL) #endif +#if defined(OS_MACOSX) + , io_surface_id(0) +#endif { } bool is_null() const { return type == EMPTY_BUFFER; } @@ -36,6 +40,10 @@ struct GpuMemoryBufferHandle { #if defined(OS_ANDROID) EGLClientBuffer native_buffer; #endif +#if defined(OS_MACOSX) + uint32 io_surface_id; +#endif + }; // Interface for creating and accessing a zero-copy GPU memory buffer. @@ -47,7 +55,7 @@ struct GpuMemoryBufferHandle { // 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. -class UI_EXPORT GpuMemoryBuffer { +class GFX_EXPORT GpuMemoryBuffer { public: enum AccessMode { READ_ONLY, diff --git a/chromium/ui/gfx/gtk_native_view_id_manager.h b/chromium/ui/gfx/gtk_native_view_id_manager.h index 242cf0939e3..44219209273 100644 --- a/chromium/ui/gfx/gtk_native_view_id_manager.h +++ b/chromium/ui/gfx/gtk_native_view_id_manager.h @@ -31,7 +31,7 @@ struct _GtkPreserveWindow; // 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 UI_EXPORT GtkNativeViewManager { +class GFX_EXPORT GtkNativeViewManager { public: // Returns the singleton instance. static GtkNativeViewManager* GetInstance(); diff --git a/chromium/ui/gfx/gtk_preserve_window.h b/chromium/ui/gfx/gtk_preserve_window.h index f48be3f2bdb..5b5198bf56f 100644 --- a/chromium/ui/gfx/gtk_preserve_window.h +++ b/chromium/ui/gfx/gtk_preserve_window.h @@ -46,25 +46,25 @@ struct _GtkPreserveWindowClass { GtkFixedClass parent_class; }; -UI_EXPORT GType gtk_preserve_window_get_type() G_GNUC_CONST; -UI_EXPORT GtkWidget* gtk_preserve_window_new(); +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. -UI_EXPORT gboolean gtk_preserve_window_get_preserve(GtkPreserveWindow* widget); -UI_EXPORT void gtk_preserve_window_set_preserve(GtkPreserveWindow* widget, - gboolean value); +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). -UI_EXPORT void gtk_preserve_window_delegate_resize(GtkPreserveWindow* widget, - gboolean delegate); +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. -UI_EXPORT void gtk_preserve_window_set_accessible_factory( +GFX_EXPORT void gtk_preserve_window_set_accessible_factory( GtkPreserveWindow* widget, AtkObject* (*factory)(void* userdata), gpointer userdata); diff --git a/chromium/ui/gfx/gtk_util.h b/chromium/ui/gfx/gtk_util.h index 5672bbd8f12..91f864bbe4c 100644 --- a/chromium/ui/gfx/gtk_util.h +++ b/chromium/ui/gfx/gtk_util.h @@ -24,28 +24,28 @@ 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. -UI_EXPORT void GtkInitFromCommandLine(const CommandLine& command_line); -UI_EXPORT void GdkInitFromCommandLine(const CommandLine& command_line); +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. -UI_EXPORT GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap); +GFX_EXPORT GdkPixbuf* GdkPixbufFromSkBitmap(const SkBitmap& bitmap); // Modify the given region by subtracting the given rectangles. -UI_EXPORT void SubtractRectanglesFromRegion(GdkRegion* region, - const std::vector<Rect>& cutouts); +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. -UI_EXPORT GdkCursor* GetCursor(int type); +GFX_EXPORT GdkCursor* GetCursor(int type); // Initialize some GTK settings so that our dialogs are consistent. -UI_EXPORT void InitRCStyles(); +GFX_EXPORT void InitRCStyles(); // Queries GtkSettings for the cursor blink cycle time. Returns a 0 duration if // blinking is disabled. -UI_EXPORT base::TimeDelta GetCursorBlinkCycle(); +GFX_EXPORT base::TimeDelta GetCursorBlinkCycle(); } // namespace gfx diff --git a/chromium/ui/gfx/icon_util.h b/chromium/ui/gfx/icon_util.h index d56f5a10df3..0cb35088147 100644 --- a/chromium/ui/gfx/icon_util.h +++ b/chromium/ui/gfx/icon_util.h @@ -57,7 +57,7 @@ class SkBitmap; // ::DestroyIcon(icon); // /////////////////////////////////////////////////////////////////////////////// -class UI_EXPORT IconUtil { +class GFX_EXPORT IconUtil { public: // The size of the large icon entries in .ico files on Windows Vista+. static const int kLargeIconSize = 256; diff --git a/chromium/ui/gfx/image/cairo_cached_surface.h b/chromium/ui/gfx/image/cairo_cached_surface.h index 7c0204aa81b..ceece4ba2d2 100644 --- a/chromium/ui/gfx/image/cairo_cached_surface.h +++ b/chromium/ui/gfx/image/cairo_cached_surface.h @@ -27,7 +27,7 @@ namespace gfx { // 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 UI_EXPORT CairoCachedSurface { +class GFX_EXPORT CairoCachedSurface { public: CairoCachedSurface(); ~CairoCachedSurface(); diff --git a/chromium/ui/gfx/image/canvas_image_source.cc b/chromium/ui/gfx/image/canvas_image_source.cc index 747625ac60d..b336b311810 100644 --- a/chromium/ui/gfx/image/canvas_image_source.cc +++ b/chromium/ui/gfx/image/canvas_image_source.cc @@ -6,7 +6,6 @@ #include "base/logging.h" #include "ui/gfx/canvas.h" -#include "ui/base/layout.h" namespace gfx { @@ -18,9 +17,8 @@ CanvasImageSource::CanvasImageSource(const gfx::Size& size, bool is_opaque) is_opaque_(is_opaque) { } -gfx::ImageSkiaRep CanvasImageSource::GetImageForScale( - ui::ScaleFactor scale_factor) { - gfx::Canvas canvas(size_, scale_factor, is_opaque_); +gfx::ImageSkiaRep CanvasImageSource::GetImageForScale(float scale) { + gfx::Canvas canvas(size_, scale, is_opaque_); Draw(&canvas); return canvas.ExtractImageRep(); } diff --git a/chromium/ui/gfx/image/canvas_image_source.h b/chromium/ui/gfx/image/canvas_image_source.h index 8373387326c..0ce170dfd9c 100644 --- a/chromium/ui/gfx/image/canvas_image_source.h +++ b/chromium/ui/gfx/image/canvas_image_source.h @@ -19,7 +19,7 @@ class ImageSkiaRep; // a scale factor using gfx::Canvas. It creates a new Canvas // with target scale factor and generates ImageSkiaRep when drawing is // completed. -class UI_EXPORT CanvasImageSource : public gfx::ImageSkiaSource { +class GFX_EXPORT CanvasImageSource : public gfx::ImageSkiaSource { public: CanvasImageSource(const gfx::Size& size, bool is_opaque); @@ -30,8 +30,7 @@ class UI_EXPORT CanvasImageSource : public gfx::ImageSkiaSource { const gfx::Size& size() const { return size_; }; // Overridden from gfx::ImageSkiaSource. - virtual gfx::ImageSkiaRep GetImageForScale( - ui::ScaleFactor scale_factor) OVERRIDE; + virtual gfx::ImageSkiaRep GetImageForScale(float scale) OVERRIDE; protected: virtual ~CanvasImageSource() {} diff --git a/chromium/ui/gfx/image/image.cc b/chromium/ui/gfx/image/image.cc index f089c837504..91b9e69b289 100644 --- a/chromium/ui/gfx/image/image.cc +++ b/chromium/ui/gfx/image/image.cc @@ -43,7 +43,7 @@ const ImageSkia ImageSkiaFromGdkPixbuf(GdkPixbuf* pixbuf) { CHECK(pixbuf); gfx::Canvas canvas(gfx::Size(gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf)), - ui::SCALE_FACTOR_100P, + 1.0f, false); skia::ScopedPlatformPaint scoped_platform_paint(canvas.sk_canvas()); cairo_t* cr = scoped_platform_paint.GetPlatformSurface(); @@ -65,7 +65,7 @@ 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_factor == ui::SCALE_FACTOR_100P) + if (image_png_reps[i].scale == 1.0f) png_bytes = image_png_reps[i].raw_data; } @@ -142,7 +142,7 @@ ImageSkia* GetErrorImageSkia() { bitmap.setConfig(SkBitmap::kARGB_8888_Config, 16, 16); bitmap.allocPixels(); bitmap.eraseRGB(0xff, 0, 0); - return new gfx::ImageSkia(gfx::ImageSkiaRep(bitmap, ui::SCALE_FACTOR_100P)); + return new gfx::ImageSkia(gfx::ImageSkiaRep(bitmap, 1.0f)); } ImageSkia* ImageSkiaFromPNG( @@ -159,23 +159,22 @@ ImageSkia* ImageSkiaFromPNG( if (!gfx::PNGCodec::Decode(raw_data->front(), raw_data->size(), &bitmap)) { LOG(ERROR) << "Unable to decode PNG for " - << ui::GetScaleFactorScale(image_png_reps[i].scale_factor) + << image_png_reps[i].scale << "."; return GetErrorImageSkia(); } image_skia->AddRepresentation(gfx::ImageSkiaRep( - bitmap, image_png_reps[i].scale_factor)); + bitmap, image_png_reps[i].scale)); } return image_skia.release(); } scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia( const ImageSkia* image_skia) { - ImageSkiaRep image_skia_rep = image_skia->GetRepresentation( - ui::SCALE_FACTOR_100P); + ImageSkiaRep image_skia_rep = image_skia->GetRepresentation(1.0f); scoped_refptr<base::RefCountedBytes> png_bytes(new base::RefCountedBytes()); - if (image_skia_rep.scale_factor() != ui::SCALE_FACTOR_100P || + if (image_skia_rep.scale() != 1.0f || !gfx::PNGCodec::EncodeBGRASkBitmap(image_skia_rep.sk_bitmap(), false, &png_bytes->data())) { return NULL; @@ -274,7 +273,7 @@ class ImageRepPNG : public ImageRep { if (!size_cache_) { for (std::vector<ImagePNGRep>::const_iterator it = image_reps().begin(); it != image_reps().end(); ++it) { - if (it->scale_factor == ui::SCALE_FACTOR_100P) { + if (it->scale == 1.0f) { size_cache_.reset(new gfx::Size(it->Size())); return *size_cache_; } @@ -604,7 +603,7 @@ Image Image::CreateFrom1xPNGBytes(const unsigned char* input, 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, ui::SCALE_FACTOR_100P)); + image_reps.push_back(ImagePNGRep(raw_data, 1.0f)); return gfx::Image(image_reps); } @@ -772,7 +771,7 @@ scoped_refptr<base::RefCountedMemory> Image::As1xPNGBytes() const { const std::vector<gfx::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_factor == ui::SCALE_FACTOR_100P) + if (image_png_reps[i].scale == 1.0f) return image_png_reps[i].raw_data; } return new base::RefCountedBytes(); @@ -827,8 +826,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, - ui::SCALE_FACTOR_100P)); + image_png_reps.push_back(gfx::ImagePNGRep(png_bytes, 1.0f)); rep = new internal::ImageRepPNG(image_png_reps); AddRepresentation(rep); return png_bytes; diff --git a/chromium/ui/gfx/image/image.h b/chromium/ui/gfx/image/image.h index 00b5baa194b..d4093b74063 100644 --- a/chromium/ui/gfx/image/image.h +++ b/chromium/ui/gfx/image/image.h @@ -53,7 +53,7 @@ class ImageRep; class ImageStorage; } -class UI_EXPORT Image { +class GFX_EXPORT Image { public: enum RepresentationType { kImageRepGdk, diff --git a/chromium/ui/gfx/image/image_family.cc b/chromium/ui/gfx/image/image_family.cc index 4a43a92e01f..6719bc1ab18 100644 --- a/chromium/ui/gfx/image/image_family.cc +++ b/chromium/ui/gfx/image/image_family.cc @@ -21,6 +21,8 @@ ImageFamily::const_iterator::const_iterator( const std::map<MapKey, gfx::Image>::const_iterator& other) : map_iterator_(other) {} +ImageFamily::const_iterator::~const_iterator() {} + ImageFamily::ImageFamily() {} ImageFamily::~ImageFamily() {} diff --git a/chromium/ui/gfx/image/image_family.h b/chromium/ui/gfx/image/image_family.h index c7943713676..c092b2a87ca 100644 --- a/chromium/ui/gfx/image/image_family.h +++ b/chromium/ui/gfx/image/image_family.h @@ -25,7 +25,7 @@ class Size; // size, with high-DPI bitmap versions; use an Image or ImageSkia for that. Each // image in an ImageFamily should have a different logical size (and may also // include high-DPI representations). -class UI_EXPORT ImageFamily { +class GFX_EXPORT ImageFamily { private: // An <aspect ratio, DIP width> pair. // A 0x0 image has aspect ratio 1.0. 0xN and Nx0 images are treated as 0x0. @@ -41,13 +41,15 @@ class UI_EXPORT ImageFamily { public: // Type for iterating over all images in the family, in order. // Dereferencing this iterator returns a gfx::Image. - class UI_EXPORT const_iterator : + class GFX_EXPORT const_iterator : std::iterator<std::bidirectional_iterator_tag, const gfx::Image> { public: const_iterator(); const_iterator(const const_iterator& other); + ~const_iterator(); + const_iterator& operator++() { ++map_iterator_; return *this; diff --git a/chromium/ui/gfx/image/image_ios.mm b/chromium/ui/gfx/image/image_ios.mm index 01a3c87fbd2..126bfb491aa 100644 --- a/chromium/ui/gfx/image/image_ios.mm +++ b/chromium/ui/gfx/image/image_ios.mm @@ -11,7 +11,6 @@ #include "base/logging.h" #include "base/mac/scoped_cftyperef.h" #include "base/mac/scoped_nsobject.h" -#include "ui/base/layout.h" #include "ui/gfx/image/image_png_rep.h" #include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia_util_ios.h" @@ -48,7 +47,7 @@ UIImage* CreateErrorUIImage(float scale) { // Converts from ImagePNGRep to UIImage. UIImage* CreateUIImageFromImagePNGRep(const gfx::ImagePNGRep& image_png_rep) { - float scale = ui::GetScaleFactorScale(image_png_rep.scale_factor); + float scale = image_png_rep.scale; scoped_refptr<base::RefCountedMemory> png = image_png_rep.raw_data; CHECK(png.get()); NSData* data = [NSData dataWithBytes:png->front() length:png->size()]; @@ -74,17 +73,16 @@ scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromUIImage( UIImage* CreateUIImageFromPNG( const std::vector<gfx::ImagePNGRep>& image_png_reps) { - ui::ScaleFactor ideal_scale_factor = ui::GetMaxScaleFactor(); - float ideal_scale = ui::GetScaleFactorScale(ideal_scale_factor); + float ideal_scale = ImageSkia::GetMaxSupportedScale(); if (image_png_reps.empty()) return CreateErrorUIImage(ideal_scale); - // Find best match for |ideal_scale_factor|. + // Find best match for |ideal_scale|. float smallest_diff = std::numeric_limits<float>::max(); size_t closest_index = 0u; for (size_t i = 0; i < image_png_reps.size(); ++i) { - float scale = ui::GetScaleFactorScale(image_png_reps[i].scale_factor); + float scale = image_png_reps[i].scale; float diff = std::abs(ideal_scale - scale); if (diff < smallest_diff) { smallest_diff = diff; @@ -102,9 +100,8 @@ scoped_refptr<base::RefCountedMemory> Get1xPNGBytesFromImageSkia( // TODO(rohitrao): Rewrite the callers of this function to save the UIImage // representation in the gfx::Image. If we're generating it, we might as well // hold on to it. - const gfx::ImageSkiaRep& image_skia_rep = skia->GetRepresentation( - ui::SCALE_FACTOR_100P); - if (image_skia_rep.scale_factor() != ui::SCALE_FACTOR_100P) + const gfx::ImageSkiaRep& image_skia_rep = skia->GetRepresentation(1.0f); + if (image_skia_rep.scale() != 1.0f) return NULL; UIImage* image = UIImageFromImageSkiaRep(image_skia_rep); @@ -119,8 +116,8 @@ ImageSkia* ImageSkiaFromPNG( for (size_t i = 0; i < image_png_reps.size(); ++i) { base::scoped_nsobject<UIImage> uiimage( CreateUIImageFromImagePNGRep(image_png_reps[i])); - gfx::ImageSkiaRep image_skia_rep = ImageSkiaRepOfScaleFactorFromUIImage( - uiimage, image_png_reps[i].scale_factor); + gfx::ImageSkiaRep image_skia_rep = ImageSkiaRepOfScaleFromUIImage( + uiimage, image_png_reps[i].scale); if (!image_skia_rep.is_null()) image_skia->AddRepresentation(image_skia_rep); } diff --git a/chromium/ui/gfx/image/image_mac.mm b/chromium/ui/gfx/image/image_mac.mm index d03b48e0f4b..15a56108342 100644 --- a/chromium/ui/gfx/image/image_mac.mm +++ b/chromium/ui/gfx/image/image_mac.mm @@ -65,7 +65,7 @@ NSImage* NSImageFromPNG(const std::vector<gfx::ImagePNGRep>& image_png_reps, [[NSBitmapImageRep alloc] initWithData:ns_data]); if (!ns_image_rep) { LOG(ERROR) << "Unable to decode PNG at " - << ui::GetScaleFactorScale(image_png_reps[i].scale_factor) + << image_png_reps[i].scale << "."; return GetErrorNSImage(); } @@ -88,7 +88,7 @@ NSImage* NSImageFromPNG(const std::vector<gfx::ImagePNGRep>& image_png_reps, } if (!image.get()) { - float scale = ui::GetScaleFactorScale(image_png_reps[i].scale_factor); + float scale = image_png_reps[i].scale; NSSize image_size = NSMakeSize([ns_image_rep pixelsWide] / scale, [ns_image_rep pixelsHigh] / scale); image.reset([[NSImage alloc] initWithSize:image_size]); diff --git a/chromium/ui/gfx/image/image_mac_unittest.mm b/chromium/ui/gfx/image/image_mac_unittest.mm index 250deeb5249..2cbbd117a97 100644 --- a/chromium/ui/gfx/image/image_mac_unittest.mm +++ b/chromium/ui/gfx/image/image_mac_unittest.mm @@ -16,26 +16,26 @@ namespace { // Returns true if the structure of |ns_image| matches the structure -// described by |width|, |height|, and |scale_factors|. +// described by |width|, |height|, and |scales|. // The structure matches if: // - |ns_image| is not nil. -// - |ns_image| has NSImageReps of |scale_factors|. +// - |ns_image| has NSImageReps of |scales|. // - Each of the NSImageReps has a pixel size of [|ns_image| size] * -// scale_factor. +// scale. bool NSImageStructureMatches( NSImage* ns_image, int width, int height, - const std::vector<ui::ScaleFactor>& scale_factors) { + const std::vector<float>& scales) { if (!ns_image || [ns_image size].width != width || [ns_image size].height != height || - [ns_image representations].count != scale_factors.size()) { + [ns_image representations].count != scales.size()) { return false; } - for (size_t i = 0; i < scale_factors.size(); ++i) { - float scale = ui::GetScaleFactorScale(scale_factors[i]); + for (size_t i = 0; i < scales.size(); ++i) { + float scale = scales[i]; bool found_match = false; for (size_t j = 0; j < [ns_image representations].count; ++j) { NSImageRep* ns_image_rep = [[ns_image representations] objectAtIndex:j]; @@ -74,16 +74,14 @@ void BitmapImageRep(int width, int height, class ImageMacTest : public testing::Test { public: - ImageMacTest() - : supported_scale_factors_(gfx::test::Get1xAnd2xScaleFactors()) { + ImageMacTest() { + gfx::ImageSkia::SetSupportedScales(gfx::test::Get1xAnd2xScales()); } virtual ~ImageMacTest() { } private: - ui::test::ScopedSetSupportedScaleFactors supported_scale_factors_; - DISALLOW_COPY_AND_ASSIGN(ImageMacTest); }; @@ -110,11 +108,11 @@ TEST_F(ImageMacTest, MultiResolutionNSImageToImageSkia) { const gfx::ImageSkia* image_skia = image.ToImageSkia(); - std::vector<ui::ScaleFactor> scale_factors; - scale_factors.push_back(ui::SCALE_FACTOR_100P); - scale_factors.push_back(ui::SCALE_FACTOR_200P); + std::vector<float> scales; + scales.push_back(1.0f); + scales.push_back(2.0f); EXPECT_TRUE(gt::ImageSkiaStructureMatches(*image_skia, kWidth1x, kHeight1x, - scale_factors)); + scales)); // ToImageSkia should create a second representation. EXPECT_EQ(2u, image.RepresentationCount()); @@ -141,11 +139,11 @@ TEST_F(ImageMacTest, UnalignedMultiResolutionNSImageToImageSkia) { const gfx::ImageSkia* image_skia = image.ToImageSkia(); - std::vector<ui::ScaleFactor> scale_factors; - scale_factors.push_back(ui::SCALE_FACTOR_100P); - scale_factors.push_back(ui::SCALE_FACTOR_200P); + std::vector<float> scales; + scales.push_back(1.0f); + scales.push_back(2.0f); EXPECT_TRUE(gt::ImageSkiaStructureMatches(*image_skia, kWidth1x, kHeight1x, - scale_factors)); + scales)); // ToImageSkia should create a second representation. EXPECT_EQ(2u, image.RepresentationCount()); @@ -159,9 +157,9 @@ TEST_F(ImageMacTest, MultiResolutionImageSkiaToNSImage) { gfx::ImageSkia image_skia; image_skia.AddRepresentation(gfx::ImageSkiaRep( - gt::CreateBitmap(kWidth1x, kHeight1x), ui::SCALE_FACTOR_100P)); + gt::CreateBitmap(kWidth1x, kHeight1x), 1.0f)); image_skia.AddRepresentation(gfx::ImageSkiaRep( - gt::CreateBitmap(kWidth2x, kHeight2x), ui::SCALE_FACTOR_200P)); + gt::CreateBitmap(kWidth2x, kHeight2x), 2.0f)); gfx::Image image(image_skia); @@ -170,11 +168,10 @@ TEST_F(ImageMacTest, MultiResolutionImageSkiaToNSImage) { NSImage* ns_image = image.ToNSImage(); - std::vector<ui::ScaleFactor> scale_factors; - scale_factors.push_back(ui::SCALE_FACTOR_100P); - scale_factors.push_back(ui::SCALE_FACTOR_200P); - EXPECT_TRUE(NSImageStructureMatches(ns_image, kWidth1x, kHeight1x, - scale_factors)); + std::vector<float> scales; + scales.push_back(1.0f); + scales.push_back(2.0f); + EXPECT_TRUE(NSImageStructureMatches(ns_image, kWidth1x, kHeight1x, scales)); // Request for NSImage* should create a second representation. EXPECT_EQ(2u, image.RepresentationCount()); @@ -187,17 +184,16 @@ TEST_F(ImageMacTest, MultiResolutionPNGToNSImage) { scoped_refptr<base::RefCountedMemory> bytes1x = gt::CreatePNGBytes(kSize1x); scoped_refptr<base::RefCountedMemory> bytes2x = gt::CreatePNGBytes(kSize2x); std::vector<gfx::ImagePNGRep> image_png_reps; - image_png_reps.push_back(gfx::ImagePNGRep(bytes1x, ui::SCALE_FACTOR_100P)); - image_png_reps.push_back(gfx::ImagePNGRep(bytes2x, ui::SCALE_FACTOR_200P)); + image_png_reps.push_back(gfx::ImagePNGRep(bytes1x, 1.0f)); + image_png_reps.push_back(gfx::ImagePNGRep(bytes2x, 2.0f)); gfx::Image image(image_png_reps); NSImage* ns_image = image.ToNSImage(); - std::vector<ui::ScaleFactor> scale_factors; - scale_factors.push_back(ui::SCALE_FACTOR_100P); - scale_factors.push_back(ui::SCALE_FACTOR_200P); - EXPECT_TRUE(NSImageStructureMatches(ns_image, kSize1x, kSize1x, - scale_factors)); + std::vector<float> scales; + scales.push_back(1.0f); + scales.push_back(2.0f); + EXPECT_TRUE(NSImageStructureMatches(ns_image, kSize1x, kSize1x, scales)); // Converting from PNG to NSImage should not go through ImageSkia. EXPECT_FALSE(image.HasRepresentation(gfx::Image::kImageRepSkia)); @@ -205,9 +201,9 @@ TEST_F(ImageMacTest, MultiResolutionPNGToNSImage) { // Convert to ImageSkia to check pixel contents of NSImageReps. gfx::ImageSkia image_skia = gfx::ImageSkiaFromNSImage(ns_image); EXPECT_TRUE(gt::IsEqual(bytes1x, - image_skia.GetRepresentation(ui::SCALE_FACTOR_100P).sk_bitmap())); + image_skia.GetRepresentation(1.0f).sk_bitmap())); EXPECT_TRUE(gt::IsEqual(bytes2x, - image_skia.GetRepresentation(ui::SCALE_FACTOR_200P).sk_bitmap())); + image_skia.GetRepresentation(2.0f).sk_bitmap())); } } // namespace diff --git a/chromium/ui/gfx/image/image_png_rep.cc b/chromium/ui/gfx/image/image_png_rep.cc index 253a5291afd..3970d2bcc02 100644 --- a/chromium/ui/gfx/image/image_png_rep.cc +++ b/chromium/ui/gfx/image/image_png_rep.cc @@ -4,6 +4,7 @@ #include "ui/gfx/image/image_png_rep.h" +#include "base/logging.h" #include "third_party/skia/include/core/SkBitmap.h" #include "ui/gfx/codec/png_codec.h" #include "ui/gfx/size.h" @@ -12,13 +13,13 @@ namespace gfx { ImagePNGRep::ImagePNGRep() : raw_data(NULL), - scale_factor(ui::SCALE_FACTOR_NONE) { + scale(1.0) { } ImagePNGRep::ImagePNGRep(const scoped_refptr<base::RefCountedMemory>& data, - ui::ScaleFactor data_scale_factor) + float data_scale) : raw_data(data), - scale_factor(data_scale_factor) { + scale(data_scale) { } ImagePNGRep::~ImagePNGRep() { diff --git a/chromium/ui/gfx/image/image_png_rep.h b/chromium/ui/gfx/image/image_png_rep.h index 7e5ce5b4e41..5c26134fa73 100644 --- a/chromium/ui/gfx/image/image_png_rep.h +++ b/chromium/ui/gfx/image/image_png_rep.h @@ -6,7 +6,6 @@ #define UI_GFX_IMAGE_IMAGE_PNG_REP_H_ #include "base/memory/ref_counted_memory.h" -#include "ui/base/layout.h" #include "ui/gfx/gfx_export.h" namespace gfx { @@ -14,10 +13,11 @@ class Size; // An ImagePNGRep represents a bitmap's png encoded data and the scale factor it // was intended for. -struct UI_EXPORT ImagePNGRep { +struct GFX_EXPORT ImagePNGRep { + public: ImagePNGRep(); ImagePNGRep(const scoped_refptr<base::RefCountedMemory>& data, - ui::ScaleFactor data_scale_factor); + float data_scale); ~ImagePNGRep(); // Width and height of the image, in pixels. @@ -27,7 +27,7 @@ struct UI_EXPORT ImagePNGRep { gfx::Size Size() const; scoped_refptr<base::RefCountedMemory> raw_data; - ui::ScaleFactor scale_factor; + float scale; }; } // namespace gfx diff --git a/chromium/ui/gfx/image/image_skia.cc b/chromium/ui/gfx/image/image_skia.cc index 1ae9874ad4d..a283117db24 100644 --- a/chromium/ui/gfx/image/image_skia.cc +++ b/chromium/ui/gfx/image/image_skia.cc @@ -26,6 +26,7 @@ gfx::ImageSkiaRep& NullImageRep() { return null_image_rep; } +std::vector<float>* g_supported_scales = NULL; } // namespace namespace internal { @@ -33,15 +34,15 @@ namespace { class Matcher { public: - explicit Matcher(ui::ScaleFactor scale_factor) : scale_factor_(scale_factor) { + explicit Matcher(float scale) : scale_(scale) { } bool operator()(const ImageSkiaRep& rep) const { - return rep.scale_factor() == scale_factor_; + return rep.scale() == scale_; } private: - ui::ScaleFactor scale_factor_; + float scale_; }; } // namespace @@ -61,11 +62,10 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>, read_only_(false) { } - ImageSkiaStorage(ImageSkiaSource* source, ui::ScaleFactor scale_factor) + ImageSkiaStorage(ImageSkiaSource* source, float scale) : source_(source), read_only_(false) { - ImageSkia::ImageSkiaReps::iterator it = - FindRepresentation(scale_factor, true); + ImageSkia::ImageSkiaReps::iterator it = FindRepresentation(scale, true); if (it == image_reps_.end() || it->is_null()) source_.reset(); else @@ -103,16 +103,15 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>, } // Returns the iterator of the image rep whose density best matches - // |scale_factor|. If the image for the |scale_factor| 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 factor (if the image doesn't exist in - // resource, for example), it will fallback to closest image rep. + // |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. std::vector<ImageSkiaRep>::iterator FindRepresentation( - ui::ScaleFactor scale_factor, bool fetch_new_image) const { + float scale, bool fetch_new_image) const { ImageSkiaStorage* non_const = const_cast<ImageSkiaStorage*>(this); - float scale = ui::GetScaleFactorScale(scale_factor); ImageSkia::ImageSkiaReps::iterator closest_iter = non_const->image_reps().end(); ImageSkia::ImageSkiaReps::iterator exact_iter = @@ -121,7 +120,7 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>, for (ImageSkia::ImageSkiaReps::iterator it = non_const->image_reps().begin(); it < image_reps_.end(); ++it) { - if (it->GetScale() == scale) { + if (it->scale() == scale) { // found exact match fetch_new_image = false; if (it->is_null()) @@ -129,7 +128,7 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>, exact_iter = it; break; } - float diff = std::abs(it->GetScale() - scale); + float diff = std::abs(it->scale() - scale); if (diff < smallest_diff && !it->is_null()) { closest_iter = it; smallest_diff = diff; @@ -140,25 +139,24 @@ 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_factor); + ImageSkiaRep image = source_->GetImageForScale(scale); // If the source returned the new image, store it. if (!image.is_null() && std::find_if(image_reps_.begin(), image_reps_.end(), - Matcher(image.scale_factor())) == image_reps_.end()) { + Matcher(image.scale())) == image_reps_.end()) { non_const->image_reps().push_back(image); } - // If the result image's scale factor isn't same as the expected - // scale factor, create null ImageSkiaRep with the |scale_factor| - // so that the next lookup will fallback to the closest scale. - if (image.is_null() || image.scale_factor() != scale_factor) { - non_const->image_reps().push_back( - ImageSkiaRep(SkBitmap(), scale_factor)); + // If the result image's scale isn't same as the expected scale, create + // null ImageSkiaRep with the |scale| so that the next lookup will + // fallback to the closest scale. + if (image.is_null() || image.scale() != scale) { + non_const->image_reps().push_back(ImageSkiaRep(SkBitmap(), scale)); } // image_reps_ must have the exact much now, so find again. - return FindRepresentation(scale_factor, false); + return FindRepresentation(scale, false); } return exact_iter != image_reps_.end() ? exact_iter : closest_iter; } @@ -170,7 +168,7 @@ class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>, DetachFromThread(); } - // Vector of bitmaps and their associated scale factor. + // Vector of bitmaps and their associated scale. std::vector<gfx::ImageSkiaRep> image_reps_; scoped_ptr<ImageSkiaSource> source_; @@ -195,8 +193,8 @@ ImageSkia::ImageSkia(ImageSkiaSource* source, const gfx::Size& size) DetachStorageFromThread(); } -ImageSkia::ImageSkia(ImageSkiaSource* source, ui::ScaleFactor scale_factor) - : storage_(new internal::ImageSkiaStorage(source, scale_factor)) { +ImageSkia::ImageSkia(ImageSkiaSource* source, float scale) + : storage_(new internal::ImageSkiaStorage(source, scale)) { DCHECK(source); if (!storage_->has_source()) storage_ = NULL; @@ -222,8 +220,27 @@ ImageSkia::~ImageSkia() { } // static +void ImageSkia::SetSupportedScales(const std::vector<float>& supported_scales) { + if (g_supported_scales != NULL) + delete g_supported_scales; + g_supported_scales = new std::vector<float>(supported_scales); + std::sort(g_supported_scales->begin(), g_supported_scales->end()); +} + +// static +const std::vector<float>& ImageSkia::GetSupportedScales() { + DCHECK(g_supported_scales != NULL); + return *g_supported_scales; +} + +// static +float ImageSkia::GetMaxSupportedScale() { + return g_supported_scales->back(); +} + +// static ImageSkia ImageSkia::CreateFrom1xBitmap(const SkBitmap& bitmap) { - return ImageSkia(ImageSkiaRep(bitmap, ui::SCALE_FACTOR_100P)); + return ImageSkia(ImageSkiaRep(bitmap, 1.0f)); } scoped_ptr<ImageSkia> ImageSkia::DeepCopy() const { @@ -254,10 +271,9 @@ void ImageSkia::AddRepresentation(const ImageSkiaRep& image_rep) { // TODO(oshima): This method should be called |SetRepresentation| // and replace the existing rep if there is already one with the - // same scale factor so that we can guarantee that a ImageSkia - // instance contians only one image rep per scale factor. This is - // not possible now as ImageLoader currently stores need - // this feature, but this needs to be fixed. + // same scale so that we can guarantee that a ImageSkia instance contains only + // one image rep per scale. This is not possible now as ImageLoader currently + // stores need this feature, but this needs to be fixed. if (isNull()) { Init(image_rep); } else { @@ -266,37 +282,34 @@ void ImageSkia::AddRepresentation(const ImageSkiaRep& image_rep) { } } -void ImageSkia::RemoveRepresentation(ui::ScaleFactor scale_factor) { +void ImageSkia::RemoveRepresentation(float scale) { if (isNull()) return; CHECK(CanModify()); ImageSkiaReps& image_reps = storage_->image_reps(); ImageSkiaReps::iterator it = - storage_->FindRepresentation(scale_factor, false); - if (it != image_reps.end() && it->scale_factor() == scale_factor) + storage_->FindRepresentation(scale, false); + if (it != image_reps.end() && it->scale() == scale) image_reps.erase(it); } -bool ImageSkia::HasRepresentation(ui::ScaleFactor scale_factor) const { +bool ImageSkia::HasRepresentation(float scale) const { if (isNull()) return false; CHECK(CanRead()); - ImageSkiaReps::iterator it = - storage_->FindRepresentation(scale_factor, false); - return (it != storage_->image_reps().end() && - it->scale_factor() == scale_factor); + ImageSkiaReps::iterator it = storage_->FindRepresentation(scale, false); + return (it != storage_->image_reps().end() && it->scale() == scale); } -const ImageSkiaRep& ImageSkia::GetRepresentation( - ui::ScaleFactor scale_factor) const { +const ImageSkiaRep& ImageSkia::GetRepresentation(float scale) const { if (isNull()) return NullImageRep(); CHECK(CanRead()); - ImageSkiaReps::iterator it = storage_->FindRepresentation(scale_factor, true); + ImageSkiaReps::iterator it = storage_->FindRepresentation(scale, true); if (it == storage_->image_reps().end()) return NullImageRep(); @@ -311,7 +324,7 @@ void ImageSkia::SetReadOnly() { void ImageSkia::MakeThreadSafe() { CHECK(storage_.get()); - EnsureRepsForSupportedScaleFactors(); + EnsureRepsForSupportedScales(); // Delete source as we no longer needs it. if (storage_.get()) storage_->DeleteSource(); @@ -354,15 +367,15 @@ std::vector<ImageSkiaRep> ImageSkia::image_reps() const { return image_reps; } -void ImageSkia::EnsureRepsForSupportedScaleFactors() const { +void ImageSkia::EnsureRepsForSupportedScales() const { + DCHECK(g_supported_scales != NULL); // Don't check ReadOnly because the source may generate images // even for read only ImageSkia. Concurrent access will be protected // by |DCHECK(CalledOnValidThread())| in FindRepresentation. if (storage_.get() && storage_->has_source()) { - std::vector<ui::ScaleFactor> supported_scale_factors = - ui::GetSupportedScaleFactors(); - for (size_t i = 0; i < supported_scale_factors.size(); ++i) - storage_->FindRepresentation(supported_scale_factors[i], true); + for (std::vector<float>::const_iterator it = g_supported_scales->begin(); + it != g_supported_scales->end(); ++it) + storage_->FindRepresentation(*it, true); } } @@ -390,8 +403,7 @@ SkBitmap& ImageSkia::GetBitmap() const { CHECK(CanRead()); #endif - ImageSkiaReps::iterator it = - storage_->FindRepresentation(ui::SCALE_FACTOR_100P, true); + ImageSkiaReps::iterator it = storage_->FindRepresentation(1.0f, true); if (it != storage_->image_reps().end()) return it->mutable_sk_bitmap(); return NullImageRep().mutable_sk_bitmap(); diff --git a/chromium/ui/gfx/image/image_skia.h b/chromium/ui/gfx/image/image_skia.h index 4bc21f877cd..fa5d070ad9b 100644 --- a/chromium/ui/gfx/image/image_skia.h +++ b/chromium/ui/gfx/image/image_skia.h @@ -34,7 +34,7 @@ class TestOnThread; // returned from ImageSkia::GetRepresentation, not on ImageSkia. // // ImageSkia is cheap to copy and intentionally supports copy semantics. -class UI_EXPORT ImageSkia { +class GFX_EXPORT ImageSkia { public: typedef std::vector<ImageSkiaRep> ImageSkiaReps; @@ -47,9 +47,9 @@ class UI_EXPORT ImageSkia { ImageSkia(ImageSkiaSource* source, const gfx::Size& size); // Creates an instance that uses the |source|. The constructor loads the image - // at |scale_factor| and uses its dimensions to calculate the size in DIP. - // ImageSkia owns |source|. - ImageSkia(ImageSkiaSource* source, ui::ScaleFactor scale_factor); + // at |scale| and uses its dimensions to calculate the size in DIP. ImageSkia + // owns |source|. + ImageSkia(ImageSkiaSource* source, float scale); explicit ImageSkia(const gfx::ImageSkiaRep& image_rep); @@ -61,6 +61,16 @@ class UI_EXPORT ImageSkia { ~ImageSkia(); + // Changes the value of GetSupportedScales() to |scales|. + static void SetSupportedScales(const std::vector<float>& scales); + + // Returns a vector with the scale factors which are supported by this + // platform, in ascending order. + static const std::vector<float>& GetSupportedScales(); + + // Returns the maximum scale supported by this platform. + static float GetMaxSupportedScale(); + // Creates an image from the passed in bitmap. // DIP width and height are based on scale factor of 1x. // Adds ref to passed in bitmap. @@ -74,7 +84,7 @@ class UI_EXPORT ImageSkia { // Note that this does NOT generate ImageSkiaReps from its source. // If you want to create a deep copy with ImageSkiaReps for supported // scale factors, you need to explicitly call - // |EnsureRepsForSupportedScaleFactors()| first. + // |EnsureRepsForSupportedScales()| first. scoped_ptr<ImageSkia> DeepCopy() const; // Returns true if this object is backed by the same ImageSkiaStorage as @@ -84,18 +94,16 @@ class UI_EXPORT ImageSkia { // Adds |image_rep| to the image reps contained by this object. void AddRepresentation(const gfx::ImageSkiaRep& image_rep); - // Removes the image rep of |scale_factor| if present. - void RemoveRepresentation(ui::ScaleFactor scale_factor); + // Removes the image rep of |scale| if present. + void RemoveRepresentation(float scale); // Returns true if the object owns an image rep whose density matches - // |scale_factor| exactly. - bool HasRepresentation(ui::ScaleFactor scale_factor) const; + // |scale| exactly. + bool HasRepresentation(float scale) const; - // Returns the image rep whose density best matches - // |scale_factor|. + // Returns the image rep whose density best matches |scale|. // Returns a null image rep if the object contains no image reps. - const gfx::ImageSkiaRep& GetRepresentation( - ui::ScaleFactor scale_factor) const; + const gfx::ImageSkiaRep& GetRepresentation(float scale) const; // Make the ImageSkia instance read-only. Note that this only prevent // modification from client code, and the storage may still be @@ -136,7 +144,7 @@ class UI_EXPORT ImageSkia { // When the source is available, generates all ImageReps for // supported scale factors. This method is defined as const as // the state change in the storage is agnostic to the caller. - void EnsureRepsForSupportedScaleFactors() const; + void EnsureRepsForSupportedScales() const; private: friend class test::TestOnThread; diff --git a/chromium/ui/gfx/image/image_skia_operations.cc b/chromium/ui/gfx/image/image_skia_operations.cc index 663156044d4..6953b59301f 100644 --- a/chromium/ui/gfx/image/image_skia_operations.cc +++ b/chromium/ui/gfx/image/image_skia_operations.cc @@ -7,7 +7,6 @@ #include "base/command_line.h" #include "base/logging.h" #include "skia/ext/image_operations.h" -#include "ui/base/layout.h" #include "ui/gfx/canvas.h" #include "ui/gfx/image/canvas_image_source.h" #include "ui/gfx/image/image_skia.h" @@ -37,14 +36,13 @@ gfx::Rect DIPToPixelBounds(gfx::Rect dip_bounds, float scale) { // Returns an image rep for the ImageSkiaSource to return to visually indicate // an error. -ImageSkiaRep GetErrorImageRep(ui::ScaleFactor scale_factor, - const gfx::Size& pixel_size) { +ImageSkiaRep GetErrorImageRep(float scale, const gfx::Size& pixel_size) { SkBitmap bitmap; bitmap.setConfig( SkBitmap::kARGB_8888_Config, pixel_size.width(), pixel_size.height()); bitmap.allocPixels(); bitmap.eraseColor(SK_ColorRED); - return gfx::ImageSkiaRep(bitmap, scale_factor); + return gfx::ImageSkiaRep(bitmap, scale); } // A base image source class that creates an image from two source images. @@ -62,27 +60,25 @@ class BinaryImageSource : public gfx::ImageSkiaSource { } // gfx::ImageSkiaSource overrides: - virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { - ImageSkiaRep first_rep = first_.GetRepresentation(scale_factor); - ImageSkiaRep second_rep = second_.GetRepresentation(scale_factor); + virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE { + ImageSkiaRep first_rep = first_.GetRepresentation(scale); + ImageSkiaRep second_rep = second_.GetRepresentation(scale); if (first_rep.pixel_size() != second_rep.pixel_size()) { - DCHECK_NE(first_rep.scale_factor(), second_rep.scale_factor()); - if (first_rep.scale_factor() == second_rep.scale_factor()) { + DCHECK_NE(first_rep.scale(), second_rep.scale()); + if (first_rep.scale() == second_rep.scale()) { LOG(ERROR) << "ImageSkiaRep size mismatch in " << source_name_; - return GetErrorImageRep(first_rep.scale_factor(), - first_rep.pixel_size()); + return GetErrorImageRep(first_rep.scale(),first_rep.pixel_size()); } - first_rep = first_.GetRepresentation(ui::SCALE_FACTOR_100P); - second_rep = second_.GetRepresentation(ui::SCALE_FACTOR_100P); + first_rep = first_.GetRepresentation(1.0f); + second_rep = second_.GetRepresentation(1.0f); DCHECK_EQ(first_rep.pixel_width(), second_rep.pixel_width()); DCHECK_EQ(first_rep.pixel_height(), second_rep.pixel_height()); if (first_rep.pixel_size() != second_rep.pixel_size()) { LOG(ERROR) << "ImageSkiaRep size mismatch in " << source_name_; - return GetErrorImageRep(first_rep.scale_factor(), - first_rep.pixel_size()); + return GetErrorImageRep(first_rep.scale(), first_rep.pixel_size()); } } else { - DCHECK_EQ(first_rep.scale_factor(), second_rep.scale_factor()); + DCHECK_EQ(first_rep.scale(), second_rep.scale()); } return CreateImageSkiaRep(first_rep, second_rep); } @@ -121,7 +117,7 @@ class BlendingImageSource : public BinaryImageSource { const ImageSkiaRep& second_rep) const OVERRIDE { SkBitmap blended = SkBitmapOperations::CreateBlendedBitmap( first_rep.sk_bitmap(), second_rep.sk_bitmap(), alpha_); - return ImageSkiaRep(blended, first_rep.scale_factor()); + return ImageSkiaRep(blended, first_rep.scale()); } private: @@ -167,8 +163,8 @@ class TransparentImageSource : public gfx::ImageSkiaSource { private: // gfx::ImageSkiaSource overrides: - virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { - ImageSkiaRep image_rep = image_.GetRepresentation(scale_factor); + virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE { + ImageSkiaRep image_rep = image_.GetRepresentation(scale); SkBitmap alpha; alpha.setConfig(SkBitmap::kARGB_8888_Config, image_rep.pixel_width(), @@ -177,7 +173,7 @@ class TransparentImageSource : public gfx::ImageSkiaSource { alpha.eraseColor(SkColorSetARGB(alpha_ * 255, 0, 0, 0)); return ImageSkiaRep( SkBitmapOperations::CreateMaskedBitmap(image_rep.sk_bitmap(), alpha), - image_rep.scale_factor()); + image_rep.scale()); } ImageSkia image_; @@ -201,7 +197,7 @@ class MaskedImageSource : public BinaryImageSource { const ImageSkiaRep& second_rep) const OVERRIDE { return ImageSkiaRep(SkBitmapOperations::CreateMaskedBitmap( first_rep.sk_bitmap(), second_rep.sk_bitmap()), - first_rep.scale_factor()); + first_rep.scale()); } private: @@ -224,16 +220,15 @@ class TiledImageSource : public gfx::ImageSkiaSource { } // gfx::ImageSkiaSource overrides: - virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { - ImageSkiaRep source_rep = source_.GetRepresentation(scale_factor); - float scale = ui::GetScaleFactorScale(source_rep.scale_factor()); + virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE { + ImageSkiaRep source_rep = source_.GetRepresentation(scale); gfx::Rect bounds = DIPToPixelBounds(gfx::Rect(src_x_, src_y_, dst_w_, - dst_h_), scale); + dst_h_), source_rep.scale()); return ImageSkiaRep( SkBitmapOperations::CreateTiledBitmap( source_rep.sk_bitmap(), bounds.x(), bounds.y(), bounds.width(), bounds.height()), - source_rep.scale_factor()); + source_rep.scale()); } private: @@ -258,11 +253,11 @@ class HSLImageSource : public gfx::ImageSkiaSource { } // gfx::ImageSkiaSource overrides: - virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { - ImageSkiaRep image_rep = image_.GetRepresentation(scale_factor); + virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE { + ImageSkiaRep image_rep = image_.GetRepresentation(scale); return gfx::ImageSkiaRep( SkBitmapOperations::CreateHSLShiftedBitmap(image_rep.sk_bitmap(), - hsl_shift_), image_rep.scale_factor()); + hsl_shift_), image_rep.scale()); } private: @@ -288,17 +283,17 @@ class ButtonImageSource: public gfx::ImageSkiaSource { } // gfx::ImageSkiaSource overrides: - virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { - ImageSkiaRep image_rep = image_.GetRepresentation(scale_factor); - ImageSkiaRep mask_rep = mask_.GetRepresentation(scale_factor); - if (image_rep.scale_factor() != mask_rep.scale_factor()) { - image_rep = image_.GetRepresentation(ui::SCALE_FACTOR_100P); - mask_rep = mask_.GetRepresentation(ui::SCALE_FACTOR_100P); + virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE { + ImageSkiaRep image_rep = image_.GetRepresentation(scale); + ImageSkiaRep mask_rep = mask_.GetRepresentation(scale); + if (image_rep.scale() != mask_rep.scale()) { + image_rep = image_.GetRepresentation(1.0f); + mask_rep = mask_.GetRepresentation(1.0f); } return gfx::ImageSkiaRep( SkBitmapOperations::CreateButtonBackground(color_, image_rep.sk_bitmap(), mask_rep.sk_bitmap()), - image_rep.scale_factor()); + image_rep.scale()); } private: @@ -323,16 +318,15 @@ class ExtractSubsetImageSource: public gfx::ImageSkiaSource { } // gfx::ImageSkiaSource overrides: - virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { - ImageSkiaRep image_rep = image_.GetRepresentation(scale_factor); - float scale_to_pixel = ui::GetScaleFactorScale(image_rep.scale_factor()); + virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE { + ImageSkiaRep image_rep = image_.GetRepresentation(scale); SkIRect subset_bounds_in_pixel = RectToSkIRect( - DIPToPixelBounds(subset_bounds_, scale_to_pixel)); + DIPToPixelBounds(subset_bounds_, image_rep.scale())); SkBitmap dst; bool success = image_rep.sk_bitmap().extractSubset(&dst, subset_bounds_in_pixel); DCHECK(success); - return gfx::ImageSkiaRep(dst, image_rep.scale_factor()); + return gfx::ImageSkiaRep(dst, image_rep.scale()); } private: @@ -356,20 +350,19 @@ class ResizeSource : public ImageSkiaSource { virtual ~ResizeSource() {} // gfx::ImageSkiaSource overrides: - virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { - const ImageSkiaRep& image_rep = source_.GetRepresentation(scale_factor); + virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE { + const ImageSkiaRep& image_rep = source_.GetRepresentation(scale); if (image_rep.GetWidth() == target_dip_size_.width() && image_rep.GetHeight() == target_dip_size_.height()) return image_rep; - const float scale = ui::GetScaleFactorScale(scale_factor); const Size target_pixel_size = DIPToPixelSize(target_dip_size_, scale); const SkBitmap resized = skia::ImageOperations::Resize( image_rep.sk_bitmap(), resize_method_, target_pixel_size.width(), target_pixel_size.height()); - return ImageSkiaRep(resized, scale_factor); + return ImageSkiaRep(resized, scale); } private: @@ -392,10 +385,9 @@ class DropShadowSource : public ImageSkiaSource { virtual ~DropShadowSource() {} // gfx::ImageSkiaSource overrides: - virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { - const ImageSkiaRep& image_rep = source_.GetRepresentation(scale_factor); + virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE { + const ImageSkiaRep& image_rep = source_.GetRepresentation(scale); - const float scale = image_rep.GetScale(); ShadowValues shadows_in_pixel; for (size_t i = 0; i < shaodws_in_dip_.size(); ++i) shadows_in_pixel.push_back(shaodws_in_dip_[i].Scale(scale)); @@ -403,7 +395,7 @@ class DropShadowSource : public ImageSkiaSource { const SkBitmap shadow_bitmap = SkBitmapOperations::CreateDropShadow( image_rep.sk_bitmap(), shadows_in_pixel); - return ImageSkiaRep(shadow_bitmap, image_rep.scale_factor()); + return ImageSkiaRep(shadow_bitmap, image_rep.scale()); } private: @@ -425,11 +417,11 @@ class RotatedSource : public ImageSkiaSource { virtual ~RotatedSource() {} // gfx::ImageSkiaSource overrides: - virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { - const ImageSkiaRep& image_rep = source_.GetRepresentation(scale_factor); + virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE { + const ImageSkiaRep& image_rep = source_.GetRepresentation(scale); const SkBitmap rotated_bitmap = SkBitmapOperations::Rotate(image_rep.sk_bitmap(), rotation_); - return ImageSkiaRep(rotated_bitmap, image_rep.scale_factor()); + return ImageSkiaRep(rotated_bitmap, image_rep.scale()); } private: diff --git a/chromium/ui/gfx/image/image_skia_operations.h b/chromium/ui/gfx/image/image_skia_operations.h index 92da50ca1a9..5b81df7bbdb 100644 --- a/chromium/ui/gfx/image/image_skia_operations.h +++ b/chromium/ui/gfx/image/image_skia_operations.h @@ -17,7 +17,7 @@ class ImageSkia; class Rect; class Size; -class UI_EXPORT ImageSkiaOperations { +class GFX_EXPORT ImageSkiaOperations { public: // Create an image that is a blend of two others. The alpha argument // specifies the opacity of the second imag. The provided image must diff --git a/chromium/ui/gfx/image/image_skia_rep.cc b/chromium/ui/gfx/image/image_skia_rep.cc index 005b9a3f54b..f8f3acb1946 100644 --- a/chromium/ui/gfx/image/image_skia_rep.cc +++ b/chromium/ui/gfx/image/image_skia_rep.cc @@ -6,41 +6,30 @@ namespace gfx { -ImageSkiaRep::ImageSkiaRep() - : scale_factor_(ui::SCALE_FACTOR_NONE) { +ImageSkiaRep::ImageSkiaRep() : scale_(1.0f) { } ImageSkiaRep::~ImageSkiaRep() { } -ImageSkiaRep::ImageSkiaRep(const gfx::Size& size, - ui::ScaleFactor scale_factor) - : scale_factor_(scale_factor) { - float scale = ui::GetScaleFactorScale(scale_factor); +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)); bitmap_.allocPixels(); } -ImageSkiaRep::ImageSkiaRep(const SkBitmap& src, - ui::ScaleFactor scale_factor) +ImageSkiaRep::ImageSkiaRep(const SkBitmap& src, float scale) : bitmap_(src), - scale_factor_(scale_factor) { + scale_(scale) { } int ImageSkiaRep::GetWidth() const { - return static_cast<int>(bitmap_.width() / - ui::GetScaleFactorScale(scale_factor_)); + return static_cast<int>(bitmap_.width() / scale_); } int ImageSkiaRep::GetHeight() const { - return static_cast<int>(bitmap_.height() / - ui::GetScaleFactorScale(scale_factor_)); -} - -float ImageSkiaRep::GetScale() const { - return ui::GetScaleFactorScale(scale_factor_); + return static_cast<int>(bitmap_.height() / scale_); } } // namespace gfx diff --git a/chromium/ui/gfx/image/image_skia_rep.h b/chromium/ui/gfx/image/image_skia_rep.h index 6fca4111597..7a1e83709ab 100644 --- a/chromium/ui/gfx/image/image_skia_rep.h +++ b/chromium/ui/gfx/image/image_skia_rep.h @@ -6,14 +6,13 @@ #define UI_GFX_IMAGE_IMAGE_SKIA_REP_H_ #include "third_party/skia/include/core/SkBitmap.h" -#include "ui/base/layout.h" #include "ui/gfx/gfx_export.h" #include "ui/gfx/size.h" namespace gfx { // An ImageSkiaRep represents a bitmap and the scale factor it is intended for. -class UI_EXPORT ImageSkiaRep { +class GFX_EXPORT ImageSkiaRep { public: // Create null bitmap. ImageSkiaRep(); @@ -21,11 +20,11 @@ class UI_EXPORT ImageSkiaRep { // Creates a bitmap with kARGB_8888_Config config with given |size| in DIP. // This allocates pixels in the bitmap. - ImageSkiaRep(const gfx::Size& size, ui::ScaleFactor scale_factor); + ImageSkiaRep(const gfx::Size& size, float scale); - // Creates a bitmap with given scale factor. + // Creates a bitmap with given scale. // Adds ref to |src|. - ImageSkiaRep(const SkBitmap& src, ui::ScaleFactor scale_factor); + ImageSkiaRep(const SkBitmap& src, float scale); // Returns true if the backing bitmap is null. bool is_null() const { return bitmap_.isNull(); } @@ -42,8 +41,7 @@ class UI_EXPORT ImageSkiaRep { } // Retrieves the scale that the bitmap will be painted at. - float GetScale() const; - ui::ScaleFactor scale_factor() const { return scale_factor_; } + float scale() const { return scale_; } // Returns backing bitmap. const SkBitmap& sk_bitmap() const { return bitmap_; } @@ -53,7 +51,7 @@ class UI_EXPORT ImageSkiaRep { SkBitmap& mutable_sk_bitmap() { return bitmap_; } SkBitmap bitmap_; - ui::ScaleFactor scale_factor_; + float scale_; }; } // namespace gfx diff --git a/chromium/ui/gfx/image/image_skia_source.h b/chromium/ui/gfx/image/image_skia_source.h index ed38e1c9389..6250032292b 100644 --- a/chromium/ui/gfx/image/image_skia_source.h +++ b/chromium/ui/gfx/image/image_skia_source.h @@ -5,22 +5,23 @@ #ifndef UI_GFX_IMAGE_IMAGE_SKIA_SOURCE_H_ #define UI_GFX_IMAGE_IMAGE_SKIA_SOURCE_H_ -#include "ui/base/layout.h" +#include <vector> + #include "ui/gfx/gfx_export.h" namespace gfx { class ImageSkiaRep; -class UI_EXPORT ImageSkiaSource { +class GFX_EXPORT ImageSkiaSource { public: virtual ~ImageSkiaSource() {} - // Returns the ImageSkiaRep for the given |scale_factor|. ImageSkia - // caches the returned ImageSkiaRep and calls this method only if it - // doesn't have ImageSkaiRep for given |scale_factor|. There is - // no need for the implementation to cache the image. - virtual gfx::ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) = 0; + // Returns the ImageSkiaRep for the given |scale|. ImageSkia caches the + // returned ImageSkiaRep and calls this method only if it doesn't have + // ImageSkiaRep for given |scale|. There is no need for the implementation to + // cache the image. + virtual gfx::ImageSkiaRep GetImageForScale(float scale) = 0; }; } // namespace gfx diff --git a/chromium/ui/gfx/image/image_skia_unittest.cc b/chromium/ui/gfx/image/image_skia_unittest.cc index fd17453f8f9..0047822122b 100644 --- a/chromium/ui/gfx/image/image_skia_unittest.cc +++ b/chromium/ui/gfx/image/image_skia_unittest.cc @@ -8,7 +8,6 @@ #include "base/threading/simple_thread.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkBitmap.h" -#include "ui/base/layout.h" #include "ui/gfx/image/image_skia_rep.h" #include "ui/gfx/image/image_skia_source.h" #include "ui/gfx/size.h" @@ -32,7 +31,7 @@ class FixedSource : public ImageSkiaSource { virtual ~FixedSource() { } - virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { + virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE { return image_; } @@ -49,8 +48,8 @@ class DynamicSource : public ImageSkiaSource { virtual ~DynamicSource() { } - virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { - return gfx::ImageSkiaRep(size_, scale_factor); + virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE { + return gfx::ImageSkiaRep(size_, scale); } private: @@ -67,7 +66,7 @@ class NullSource: public ImageSkiaSource { virtual ~NullSource() { } - virtual ImageSkiaRep GetImageForScale(ui::ScaleFactor scale_factor) OVERRIDE { + virtual ImageSkiaRep GetImageForScale(float scale) OVERRIDE { return gfx::ImageSkiaRep(); } @@ -115,58 +114,55 @@ class TestOnThread : public base::SimpleThread { } // namespace test TEST(ImageSkiaTest, FixedSource) { - ImageSkiaRep image(Size(100, 200), ui::SCALE_FACTOR_100P); + ImageSkiaRep image(Size(100, 200), 1.0f); ImageSkia image_skia(new FixedSource(image), Size(100, 200)); EXPECT_EQ(0U, image_skia.image_reps().size()); - const ImageSkiaRep& result_100p = - image_skia.GetRepresentation(ui::SCALE_FACTOR_100P); + const ImageSkiaRep& result_100p = image_skia.GetRepresentation(1.0f); EXPECT_EQ(100, result_100p.GetWidth()); EXPECT_EQ(200, result_100p.GetHeight()); - EXPECT_EQ(ui::SCALE_FACTOR_100P, result_100p.scale_factor()); + EXPECT_EQ(1.0f, result_100p.scale()); EXPECT_EQ(1U, image_skia.image_reps().size()); - const ImageSkiaRep& result_200p = - image_skia.GetRepresentation(ui::SCALE_FACTOR_200P); + const ImageSkiaRep& result_200p = image_skia.GetRepresentation(2.0f); EXPECT_EQ(100, result_200p.GetWidth()); EXPECT_EQ(200, result_200p.GetHeight()); EXPECT_EQ(100, result_200p.pixel_width()); EXPECT_EQ(200, result_200p.pixel_height()); - EXPECT_EQ(ui::SCALE_FACTOR_100P, result_200p.scale_factor()); + EXPECT_EQ(1.0f, result_200p.scale()); EXPECT_EQ(1U, image_skia.image_reps().size()); // Get the representation again and make sure it doesn't // generate new image skia rep. - image_skia.GetRepresentation(ui::SCALE_FACTOR_100P); - image_skia.GetRepresentation(ui::SCALE_FACTOR_200P); + image_skia.GetRepresentation(1.0f); + image_skia.GetRepresentation(2.0f); EXPECT_EQ(1U, image_skia.image_reps().size()); } TEST(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(ui::SCALE_FACTOR_100P); + const ImageSkiaRep& result_100p = image_skia.GetRepresentation(1.0f); EXPECT_EQ(100, result_100p.GetWidth()); EXPECT_EQ(200, result_100p.GetHeight()); - EXPECT_EQ(ui::SCALE_FACTOR_100P, result_100p.scale_factor()); + EXPECT_EQ(1.0f, result_100p.scale()); EXPECT_EQ(1U, image_skia.image_reps().size()); const ImageSkiaRep& result_200p = - image_skia.GetRepresentation(ui::SCALE_FACTOR_200P); + image_skia.GetRepresentation(2.0f); EXPECT_EQ(100, result_200p.GetWidth()); EXPECT_EQ(200, result_200p.GetHeight()); EXPECT_EQ(200, result_200p.pixel_width()); EXPECT_EQ(400, result_200p.pixel_height()); - EXPECT_EQ(ui::SCALE_FACTOR_200P, result_200p.scale_factor()); + EXPECT_EQ(2.0f, result_200p.scale()); EXPECT_EQ(2U, image_skia.image_reps().size()); // Get the representation again and make sure it doesn't // generate new image skia rep. - image_skia.GetRepresentation(ui::SCALE_FACTOR_100P); + image_skia.GetRepresentation(1.0f); EXPECT_EQ(2U, image_skia.image_reps().size()); - image_skia.GetRepresentation(ui::SCALE_FACTOR_200P); + image_skia.GetRepresentation(2.0f); EXPECT_EQ(2U, image_skia.image_reps().size()); } @@ -182,16 +178,16 @@ TEST(ImageSkiaTest, ManyRepsPerScaleFactor) { // Simulate a source which loads images on a delay. Upon // GetImageForScaleFactor, it immediately returns null and starts loading // image reps slowly. - image.GetRepresentation(ui::SCALE_FACTOR_100P); - image.GetRepresentation(ui::SCALE_FACTOR_200P); + image.GetRepresentation(1.0f); + image.GetRepresentation(2.0f); // After a lengthy amount of simulated time, finally loaded image reps. image.AddRepresentation(ImageSkiaRep( - gfx::Size(kSmallIcon1x, kSmallIcon1x), ui::SCALE_FACTOR_100P)); + gfx::Size(kSmallIcon1x, kSmallIcon1x), 1.0f)); image.AddRepresentation(ImageSkiaRep( - gfx::Size(kSmallIcon2x, kSmallIcon2x), ui::SCALE_FACTOR_200P)); + gfx::Size(kSmallIcon2x, kSmallIcon2x), 2.0f)); image.AddRepresentation(ImageSkiaRep( - gfx::Size(kLargeIcon1x, kLargeIcon1x), ui::SCALE_FACTOR_100P)); + gfx::Size(kLargeIcon1x, kLargeIcon1x), 1.0f)); std::vector<ImageSkiaRep> image_reps = image.image_reps(); EXPECT_EQ(3u, image_reps.size()); @@ -199,9 +195,9 @@ TEST(ImageSkiaTest, ManyRepsPerScaleFactor) { int num_1x = 0; int num_2x = 0; for (size_t i = 0; i < image_reps.size(); ++i) { - if (image_reps[i].scale_factor() == ui::SCALE_FACTOR_100P) + if (image_reps[i].scale() == 1.0f) num_1x++; - else if (image_reps[i].scale_factor() == ui::SCALE_FACTOR_200P) + else if (image_reps[i].scale() == 2.0f) num_2x++; } EXPECT_EQ(2, num_1x); @@ -218,9 +214,9 @@ TEST(ImageSkiaTest, GetBitmap) { TEST(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), ui::SCALE_FACTOR_100P)); + ImageSkia empty_image(ImageSkiaRep(Size(100, 200), 1.0f)); ImageSkia empty_image_copy(empty_image); - empty_image.RemoveRepresentation(ui::SCALE_FACTOR_100P); + empty_image.RemoveRepresentation(1.0f); // Check that ImageSkia::bitmap() still returns a valid SkBitmap pointer for // the image and all its copies. @@ -237,12 +233,12 @@ TEST(ImageSkiaTest, BackedBySameObjectAs) { EXPECT_TRUE(image.BackedBySameObjectAs(unrelated)); image.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10), - ui::SCALE_FACTOR_100P)); + 1.0f)); ImageSkia copy = image; copy.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10), - ui::SCALE_FACTOR_200P)); + 2.0f)); unrelated.AddRepresentation(gfx::ImageSkiaRep(gfx::Size(10, 10), - ui::SCALE_FACTOR_100P)); + 1.0f)); EXPECT_TRUE(image.BackedBySameObjectAs(copy)); EXPECT_FALSE(image.BackedBySameObjectAs(unrelated)); EXPECT_FALSE(copy.BackedBySameObjectAs(unrelated)); @@ -259,7 +255,7 @@ TEST(ImageSkiaTest, EmptyOnThreadTest) { } TEST(ImageSkiaTest, StaticOnThreadTest) { - ImageSkia image(ImageSkiaRep(Size(100, 200), ui::SCALE_FACTOR_100P)); + ImageSkia image(ImageSkiaRep(Size(100, 200), 1.0f)); EXPECT_FALSE(image.IsThreadSafe()); test::TestOnThread image_on_thread(&image); @@ -365,8 +361,8 @@ TEST(ImageSkiaTest, SourceOnThreadTest) { image.MakeThreadSafe(); EXPECT_TRUE(image.IsThreadSafe()); // Check if image reps are generated for supported scale factors. - EXPECT_EQ(ui::GetSupportedScaleFactors().size(), - image.image_reps().size()); + EXPECT_EQ(ImageSkia::GetSupportedScales().size(), + image.image_reps().size()); test::TestOnThread threadsafe_on_thread(&image); threadsafe_on_thread.StartAndJoin(); EXPECT_TRUE(threadsafe_on_thread.can_read()); diff --git a/chromium/ui/gfx/image/image_skia_util_ios.h b/chromium/ui/gfx/image/image_skia_util_ios.h index 57c9698b955..6576ff8da7a 100644 --- a/chromium/ui/gfx/image/image_skia_util_ios.h +++ b/chromium/ui/gfx/image/image_skia_util_ios.h @@ -5,7 +5,6 @@ #ifndef UI_GFX_IMAGE_IMAGE_SKIA_UTIL_IOS_H_ #define UI_GFX_IMAGE_IMAGE_SKIA_UTIL_IOS_H_ -#include "ui/base/layout.h" #include "ui/gfx/gfx_export.h" #ifdef __OBJC__ @@ -19,24 +18,22 @@ class ImageSkia; class ImageSkiaRep; // Converts to ImageSkia from UIImage. -UI_EXPORT gfx::ImageSkia ImageSkiaFromUIImage(UIImage* image); +GFX_EXPORT gfx::ImageSkia ImageSkiaFromUIImage(UIImage* image); // Converts to an ImageSkiaRep of |scale_factor| from UIImage. -// |scale_factor| is passed explicitly in order to allow this method to be used -// with a |scale_factor| which is not supported by the platform. -// (ui::GetScaleFactorFromScale() is restricted to the platform's supported -// scale factors.) -UI_EXPORT gfx::ImageSkiaRep ImageSkiaRepOfScaleFactorFromUIImage( +// |scale| is passed explicitly in order to allow this method to be used +// with a |scale| which is not supported by the platform. +GFX_EXPORT gfx::ImageSkiaRep ImageSkiaRepOfScaleFromUIImage( UIImage* image, - ui::ScaleFactor scale_factor); + float scale); // Converts to UIImage from ImageSkia. The returned UIImage will be at the scale // of the ImageSkiaRep in |image_skia| which most closely matches the device's // scale factor (eg Retina iPad -> 2x). Returns an autoreleased UIImage. -UI_EXPORT UIImage* UIImageFromImageSkia(const gfx::ImageSkia& image_skia); +GFX_EXPORT UIImage* UIImageFromImageSkia(const gfx::ImageSkia& image_skia); // Converts to UIImage from ImageSkiaRep. Returns an autoreleased UIImage. -UI_EXPORT UIImage* UIImageFromImageSkiaRep( +GFX_EXPORT UIImage* UIImageFromImageSkiaRep( const gfx::ImageSkiaRep& image_skia_rep); } // namespace gfx diff --git a/chromium/ui/gfx/image/image_skia_util_ios.mm b/chromium/ui/gfx/image/image_skia_util_ios.mm index 0ff8978f786..77944eee4c2 100644 --- a/chromium/ui/gfx/image/image_skia_util_ios.mm +++ b/chromium/ui/gfx/image/image_skia_util_ios.mm @@ -16,39 +16,37 @@ namespace gfx { gfx::ImageSkia ImageSkiaFromUIImage(UIImage* image) { gfx::ImageSkia image_skia; - gfx::ImageSkiaRep image_skia_rep = ImageSkiaRepOfScaleFactorFromUIImage( - image, ui::GetMaxScaleFactor()); + float max_scale = ImageSkia::GetSupportedScales().back(); + gfx::ImageSkiaRep image_skia_rep = ImageSkiaRepOfScaleFromUIImage( + image, max_scale); if (!image_skia_rep.is_null()) image_skia.AddRepresentation(image_skia_rep); return image_skia; } -gfx::ImageSkiaRep ImageSkiaRepOfScaleFactorFromUIImage( - UIImage* image, - ui::ScaleFactor scale_factor) { +gfx::ImageSkiaRep ImageSkiaRepOfScaleFromUIImage(UIImage* image, float scale) { if (!image) return gfx::ImageSkiaRep(); - float scale = ui::GetScaleFactorScale(scale_factor); CGSize size = image.size; CGSize desired_size_for_scale = CGSizeMake(size.width * scale, size.height * scale); SkBitmap bitmap(gfx::CGImageToSkBitmap(image.CGImage, desired_size_for_scale, false)); - return gfx::ImageSkiaRep(bitmap, scale_factor); + return gfx::ImageSkiaRep(bitmap, scale); } UIImage* UIImageFromImageSkia(const gfx::ImageSkia& image_skia) { - return UIImageFromImageSkiaRep(image_skia.GetRepresentation( - ui::GetMaxScaleFactor())); + return UIImageFromImageSkiaRep( + image_skia.GetRepresentation(ImageSkia::GetSupportedScales().back())); } UIImage* UIImageFromImageSkiaRep(const gfx::ImageSkiaRep& image_skia_rep) { if (image_skia_rep.is_null()) return nil; - float scale = ui::GetScaleFactorScale(image_skia_rep.scale_factor()); + float scale = image_skia_rep.scale(); base::ScopedCFTypeRef<CGColorSpaceRef> color_space( CGColorSpaceCreateDeviceRGB()); return gfx::SkBitmapToUIImageWithColorSpace(image_skia_rep.sk_bitmap(), scale, diff --git a/chromium/ui/gfx/image/image_skia_util_mac.h b/chromium/ui/gfx/image/image_skia_util_mac.h index 10d05b045d4..553c3f8741d 100644 --- a/chromium/ui/gfx/image/image_skia_util_mac.h +++ b/chromium/ui/gfx/image/image_skia_util_mac.h @@ -25,21 +25,21 @@ namespace gfx { class ImageSkia; // Converts to ImageSkia from NSImage. -UI_EXPORT gfx::ImageSkia ImageSkiaFromNSImage(NSImage* image); +GFX_EXPORT gfx::ImageSkia ImageSkiaFromNSImage(NSImage* image); // Resizes NSImage to |size| DIP and then converts to ImageSkia. -UI_EXPORT gfx::ImageSkia ImageSkiaFromResizedNSImage(NSImage* image, - NSSize size); +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. -UI_EXPORT gfx::ImageSkia ApplicationIconAtSize(int size); +GFX_EXPORT gfx::ImageSkia ApplicationIconAtSize(int size); // Converts to NSImage from ImageSkia. -UI_EXPORT NSImage* NSImageFromImageSkia(const gfx::ImageSkia& image_skia); +GFX_EXPORT NSImage* NSImageFromImageSkia(const gfx::ImageSkia& image_skia); // Converts to NSImage from given ImageSkia and a color space. -UI_EXPORT NSImage* NSImageFromImageSkiaWithColorSpace( +GFX_EXPORT NSImage* NSImageFromImageSkiaWithColorSpace( const gfx::ImageSkia& image_skia, CGColorSpaceRef color_space); diff --git a/chromium/ui/gfx/image/image_skia_util_mac.mm b/chromium/ui/gfx/image/image_skia_util_mac.mm index f9d0475af7f..281badc7423 100644 --- a/chromium/ui/gfx/image/image_skia_util_mac.mm +++ b/chromium/ui/gfx/image/image_skia_util_mac.mm @@ -57,24 +57,23 @@ gfx::ImageSkia ImageSkiaFromResizedNSImage(NSImage* image, if (IsNSImageEmpty(image)) return gfx::ImageSkia(); - std::vector<ui::ScaleFactor> supported_scale_factors = - ui::GetSupportedScaleFactors(); + std::vector<float> supported_scales = ImageSkia::GetSupportedScales(); gfx::ImageSkia image_skia; - for (size_t i = 0; i < supported_scale_factors.size(); ++i) { - float scale = ui::GetScaleFactorScale(supported_scale_factors[i]); + for (size_t i = 0; i < supported_scales.size(); ++i) { + float scale = supported_scales[i]; NSSize desired_size_for_scale = NSMakeSize(desired_size.width * scale, desired_size.height * scale); NSImageRep* ns_image_rep = GetNSImageRepWithPixelSize(image, desired_size_for_scale); - SkBitmap bitmap(gfx::NSImageRepToSkBitmap(ns_image_rep, - desired_size_for_scale, false)); + // TODO(dcheng): Should this function take a color space argument? + SkBitmap bitmap(gfx::NSImageRepToSkBitmapWithColorSpace(ns_image_rep, + desired_size_for_scale, false, base::mac::GetGenericRGBColorSpace())); if (bitmap.isNull()) continue; - image_skia.AddRepresentation(gfx::ImageSkiaRep(bitmap, - supported_scale_factors[i])); + image_skia.AddRepresentation(gfx::ImageSkiaRep(bitmap, scale)); } return image_skia; } @@ -90,7 +89,7 @@ NSImage* NSImageFromImageSkia(const gfx::ImageSkia& image_skia) { return nil; base::scoped_nsobject<NSImage> image([[NSImage alloc] init]); - image_skia.EnsureRepsForSupportedScaleFactors(); + image_skia.EnsureRepsForSupportedScales(); std::vector<gfx::ImageSkiaRep> image_reps = image_skia.image_reps(); for (std::vector<gfx::ImageSkiaRep>::const_iterator it = image_reps.begin(); it != image_reps.end(); ++it) { @@ -108,7 +107,7 @@ NSImage* NSImageFromImageSkiaWithColorSpace(const gfx::ImageSkia& image_skia, return nil; base::scoped_nsobject<NSImage> image([[NSImage alloc] init]); - image_skia.EnsureRepsForSupportedScaleFactors(); + image_skia.EnsureRepsForSupportedScales(); std::vector<gfx::ImageSkiaRep> image_reps = image_skia.image_reps(); for (std::vector<gfx::ImageSkiaRep>::const_iterator it = image_reps.begin(); it != image_reps.end(); ++it) { diff --git a/chromium/ui/gfx/image/image_unittest.cc b/chromium/ui/gfx/image/image_unittest.cc index 6d3c649643d..039cb13f606 100644 --- a/chromium/ui/gfx/image/image_unittest.cc +++ b/chromium/ui/gfx/image/image_unittest.cc @@ -5,7 +5,6 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkPaint.h" -#include "ui/base/layout.h" #include "ui/gfx/image/image.h" #include "ui/gfx/image/image_png_rep.h" #include "ui/gfx/image/image_skia.h" @@ -24,13 +23,23 @@ namespace { -#if defined(TOOLKIT_VIEWS) || defined(OS_ANDROID) +#if defined(TOOLKIT_VIEWS) || defined(OS_ANDROID) || \ + (defined(OS_LINUX) && !defined(USE_CAIRO)) const bool kUsesSkiaNatively = true; #else const bool kUsesSkiaNatively = false; #endif class ImageTest : public testing::Test { + public: + ImageTest() { + std::vector<float> scales; + scales.push_back(1.0f); +#if !defined(OS_IOS) + scales.push_back(2.0f); +#endif + gfx::ImageSkia::SetSupportedScales(scales); + } }; namespace gt = gfx::test; @@ -95,14 +104,14 @@ TEST_F(ImageTest, EmptyImageFromEmptyPlatformImage) { // invalid data. TEST_F(ImageTest, EmptyImageFromObviouslyInvalidPNGImage) { std::vector<gfx::ImagePNGRep> image_png_reps1; - image_png_reps1.push_back(gfx::ImagePNGRep(NULL, ui::SCALE_FACTOR_100P)); + image_png_reps1.push_back(gfx::ImagePNGRep(NULL, 1.0f)); gfx::Image image1(image_png_reps1); EXPECT_TRUE(image1.IsEmpty()); EXPECT_EQ(0U, image1.RepresentationCount()); std::vector<gfx::ImagePNGRep> image_png_reps2; image_png_reps2.push_back(gfx::ImagePNGRep( - new base::RefCountedBytes(), ui::SCALE_FACTOR_100P)); + new base::RefCountedBytes(), 1.0f)); gfx::Image image2(image_png_reps2); EXPECT_TRUE(image2.IsEmpty()); EXPECT_EQ(0U, image2.RepresentationCount()); @@ -166,7 +175,7 @@ TEST_F(ImageTest, ImageNo1xToPNG) { const int kSize2x = 50; gfx::ImageSkia image_skia; image_skia.AddRepresentation(gfx::ImageSkiaRep(gt::CreateBitmap( - kSize2x, kSize2x), ui::SCALE_FACTOR_200P)); + kSize2x, kSize2x), 2.0f)); gfx::Image image1(image_skia); scoped_refptr<base::RefCountedMemory> png_bytes1 = image1.As1xPNGBytes(); EXPECT_TRUE(png_bytes1.get()); @@ -174,7 +183,7 @@ TEST_F(ImageTest, ImageNo1xToPNG) { std::vector<gfx::ImagePNGRep> image_png_reps; image_png_reps.push_back(gfx::ImagePNGRep( - gt::CreatePNGBytes(kSize2x), ui::SCALE_FACTOR_200P)); + gt::CreatePNGBytes(kSize2x), 2.0f)); gfx::Image image2(image_png_reps); EXPECT_FALSE(image2.IsEmpty()); EXPECT_EQ(0, image2.Width()); @@ -192,9 +201,9 @@ TEST_F(ImageTest, CreateExtractPNGBytes) { scoped_refptr<base::RefCountedMemory> bytes1x = gt::CreatePNGBytes(kSize1x); std::vector<gfx::ImagePNGRep> image_png_reps; - image_png_reps.push_back(gfx::ImagePNGRep(bytes1x, ui::SCALE_FACTOR_100P)); + image_png_reps.push_back(gfx::ImagePNGRep(bytes1x, 1.0f)); image_png_reps.push_back(gfx::ImagePNGRep( - gt::CreatePNGBytes(kSize2x), ui::SCALE_FACTOR_200P)); + gt::CreatePNGBytes(kSize2x), 2.0f)); gfx::Image image(image_png_reps); EXPECT_FALSE(image.IsEmpty()); @@ -212,9 +221,9 @@ TEST_F(ImageTest, MultiResolutionImageSkiaToPNG) { SkBitmap bitmap_1x = gt::CreateBitmap(kSize1x, kSize1x); gfx::ImageSkia image_skia; image_skia.AddRepresentation(gfx::ImageSkiaRep(bitmap_1x, - ui::SCALE_FACTOR_100P)); + 1.0f)); image_skia.AddRepresentation(gfx::ImageSkiaRep(gt::CreateBitmap( - kSize2x, kSize2x), ui::SCALE_FACTOR_200P)); + kSize2x, kSize2x), 2.0f)); gfx::Image image(image_skia); EXPECT_TRUE(gt::IsEqual(image.As1xPNGBytes(), bitmap_1x)); @@ -229,20 +238,20 @@ TEST_F(ImageTest, MultiResolutionPNGToImageSkia) { scoped_refptr<base::RefCountedMemory> bytes2x = gt::CreatePNGBytes(kSize2x); std::vector<gfx::ImagePNGRep> image_png_reps; - image_png_reps.push_back(gfx::ImagePNGRep(bytes1x, ui::SCALE_FACTOR_100P)); - image_png_reps.push_back(gfx::ImagePNGRep(bytes2x, ui::SCALE_FACTOR_200P)); + image_png_reps.push_back(gfx::ImagePNGRep(bytes1x, 1.0f)); + image_png_reps.push_back(gfx::ImagePNGRep(bytes2x, 2.0f)); gfx::Image image(image_png_reps); - std::vector<ui::ScaleFactor> scale_factors; - scale_factors.push_back(ui::SCALE_FACTOR_100P); - scale_factors.push_back(ui::SCALE_FACTOR_200P); + std::vector<float> scales; + scales.push_back(1.0f); + scales.push_back(2.0f); gfx::ImageSkia image_skia = image.AsImageSkia(); EXPECT_TRUE(gt::ImageSkiaStructureMatches(image_skia, kSize1x, kSize1x, - scale_factors)); + scales)); EXPECT_TRUE(gt::IsEqual(bytes1x, - image_skia.GetRepresentation(ui::SCALE_FACTOR_100P).sk_bitmap())); + image_skia.GetRepresentation(1.0f).sk_bitmap())); EXPECT_TRUE(gt::IsEqual(bytes2x, - image_skia.GetRepresentation(ui::SCALE_FACTOR_200P).sk_bitmap())); + image_skia.GetRepresentation(2.0f).sk_bitmap())); } TEST_F(ImageTest, MultiResolutionPNGToPlatform) { @@ -252,18 +261,18 @@ TEST_F(ImageTest, MultiResolutionPNGToPlatform) { scoped_refptr<base::RefCountedMemory> bytes1x = gt::CreatePNGBytes(kSize1x); scoped_refptr<base::RefCountedMemory> bytes2x = gt::CreatePNGBytes(kSize2x); std::vector<gfx::ImagePNGRep> image_png_reps; - image_png_reps.push_back(gfx::ImagePNGRep(bytes1x, ui::SCALE_FACTOR_100P)); - image_png_reps.push_back(gfx::ImagePNGRep(bytes2x, ui::SCALE_FACTOR_200P)); + image_png_reps.push_back(gfx::ImagePNGRep(bytes1x, 1.0f)); + image_png_reps.push_back(gfx::ImagePNGRep(bytes2x, 2.0f)); gfx::Image from_png(image_png_reps); gfx::Image from_platform(gt::CopyPlatformType(from_png)); #if defined(OS_IOS) // On iOS the platform type (UIImage) only supports one resolution. - std::vector<ui::ScaleFactor> scale_factors = ui::GetSupportedScaleFactors(); - EXPECT_EQ(scale_factors.size(), 1U); - if (scale_factors[0] == ui::SCALE_FACTOR_100P) + std::vector<float> scales = gfx::ImageSkia::GetSupportedScales(); + EXPECT_EQ(scales.size(), 1U); + if (scales[0] == 1.0f) EXPECT_TRUE(gt::IsEqual(bytes1x, from_platform.AsBitmap())); - else if (scale_factors[0] == ui::SCALE_FACTOR_200P) + else if (scales[0] == 2.0f) EXPECT_TRUE(gt::IsEqual(bytes2x, from_platform.AsBitmap())); else ADD_FAILURE() << "Unexpected platform scale factor."; @@ -281,7 +290,7 @@ TEST_F(ImageTest, PlatformToPNGEncodeAndDecode) { EXPECT_TRUE(image.HasRepresentation(gfx::Image::kImageRepPNG)); std::vector<gfx::ImagePNGRep> image_png_reps; - image_png_reps.push_back(gfx::ImagePNGRep(png_data, ui::SCALE_FACTOR_100P)); + image_png_reps.push_back(gfx::ImagePNGRep(png_data, 1.0f)); gfx::Image from_png(image_png_reps); EXPECT_TRUE(from_png.HasRepresentation(gfx::Image::kImageRepPNG)); @@ -292,15 +301,13 @@ TEST_F(ImageTest, PlatformToPNGEncodeAndDecode) { // sure these work with the Skia Encode/Decode. TEST_F(ImageTest, PNGEncodeFromSkiaDecodeToPlatform) { // Force the conversion sequence skia to png to platform_type. - ui::ScaleFactor ideal_scale_factor = ui::GetScaleFactorFromScale(1.0f); - gfx::Image from_bitmap = gfx::Image::CreateFrom1xBitmap( gt::CreateBitmap(25, 25)); scoped_refptr<base::RefCountedMemory> png_bytes = from_bitmap.As1xPNGBytes(); std::vector<gfx::ImagePNGRep> image_png_reps; - image_png_reps.push_back(gfx::ImagePNGRep(png_bytes, ideal_scale_factor)); + image_png_reps.push_back(gfx::ImagePNGRep(png_bytes, 1.0f)); gfx::Image from_png(image_png_reps); gfx::Image from_platform(gt::CopyPlatformType(from_png)); @@ -315,7 +322,7 @@ TEST_F(ImageTest, PNGEncodeFromPlatformDecodeToSkia) { scoped_refptr<base::RefCountedMemory> png_bytes = from_platform.As1xPNGBytes(); std::vector<gfx::ImagePNGRep> image_png_reps; - image_png_reps.push_back(gfx::ImagePNGRep(png_bytes, ui::SCALE_FACTOR_100P)); + image_png_reps.push_back(gfx::ImagePNGRep(png_bytes, 1.0f)); gfx::Image from_png(image_png_reps); EXPECT_TRUE(gt::IsEqual(from_platform.AsBitmap(), from_png.AsBitmap())); @@ -327,7 +334,7 @@ TEST_F(ImageTest, PNGDecodeToSkiaFailure) { invalid_bytes->data().push_back('0'); std::vector<gfx::ImagePNGRep> image_png_reps; image_png_reps.push_back(gfx::ImagePNGRep( - invalid_bytes, ui::SCALE_FACTOR_100P)); + invalid_bytes, 1.0f)); gfx::Image image(image_png_reps); gt::CheckImageIndicatesPNGDecodeFailure(image); } @@ -338,7 +345,7 @@ TEST_F(ImageTest, PNGDecodeToPlatformFailure) { invalid_bytes->data().push_back('0'); std::vector<gfx::ImagePNGRep> image_png_reps; image_png_reps.push_back(gfx::ImagePNGRep( - invalid_bytes, ui::SCALE_FACTOR_100P)); + invalid_bytes, 1.0f)); gfx::Image from_png(image_png_reps); gfx::Image from_platform(gt::CopyPlatformType(from_png)); gt::CheckImageIndicatesPNGDecodeFailure(from_platform); @@ -531,9 +538,9 @@ TEST_F(ImageTest, SkBitmapConversionPreservesTransparency) { const int width = 50; const int height = 50; SkBitmap bitmap; - bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height); + bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height, 0, + kPremul_SkAlphaType); bitmap.allocPixels(); - bitmap.setIsOpaque(false); bitmap.eraseARGB(0, 0, 255, 0); // Paint the upper half of the image in red (lower half is transparent). @@ -636,16 +643,16 @@ TEST_F(ImageTest, MultiResolutionImageSkia) { gfx::ImageSkia image_skia; image_skia.AddRepresentation(gfx::ImageSkiaRep( gt::CreateBitmap(kWidth1x, kHeight1x), - ui::SCALE_FACTOR_100P)); + 1.0f)); image_skia.AddRepresentation(gfx::ImageSkiaRep( gt::CreateBitmap(kWidth2x, kHeight2x), - ui::SCALE_FACTOR_200P)); + 2.0f)); - std::vector<ui::ScaleFactor> scale_factors; - scale_factors.push_back(ui::SCALE_FACTOR_100P); - scale_factors.push_back(ui::SCALE_FACTOR_200P); + std::vector<float> scales; + scales.push_back(1.0f); + scales.push_back(2.0f); EXPECT_TRUE(gt::ImageSkiaStructureMatches(image_skia, kWidth1x, kHeight1x, - scale_factors)); + scales)); // Check that the image has a single representation. gfx::Image image(image_skia); @@ -661,13 +668,13 @@ TEST_F(ImageTest, RemoveFromMultiResolutionImageSkia) { gfx::ImageSkia image_skia; image_skia.AddRepresentation(gfx::ImageSkiaRep( - gt::CreateBitmap(kWidth2x, kHeight2x), ui::SCALE_FACTOR_200P)); + gt::CreateBitmap(kWidth2x, kHeight2x), 2.0f)); EXPECT_EQ(1u, image_skia.image_reps().size()); - image_skia.RemoveRepresentation(ui::SCALE_FACTOR_100P); + image_skia.RemoveRepresentation(1.0f); EXPECT_EQ(1u, image_skia.image_reps().size()); - image_skia.RemoveRepresentation(ui::SCALE_FACTOR_200P); + image_skia.RemoveRepresentation(2.0f); EXPECT_EQ(0u, image_skia.image_reps().size()); } @@ -679,7 +686,7 @@ TEST_F(ImageTest, OwnershipTest) { SkBitmap bitmap(gt::CreateBitmap(10, 10)); EXPECT_TRUE(!bitmap.isNull()); image = gfx::Image(gfx::ImageSkia( - gfx::ImageSkiaRep(bitmap, ui::SCALE_FACTOR_100P))); + gfx::ImageSkiaRep(bitmap, 1.0f))); } EXPECT_TRUE(!image.ToSkBitmap()->isNull()); } diff --git a/chromium/ui/gfx/image/image_unittest_util.cc b/chromium/ui/gfx/image/image_unittest_util.cc index ef59eb61636..4baf30a4cc6 100644 --- a/chromium/ui/gfx/image/image_unittest_util.cc +++ b/chromium/ui/gfx/image/image_unittest_util.cc @@ -48,11 +48,11 @@ bool ColorsClose(SkColor color1, SkColor color2) { } // namespace -std::vector<ui::ScaleFactor> Get1xAnd2xScaleFactors() { - std::vector<ui::ScaleFactor> scale_factors; - scale_factors.push_back(ui::SCALE_FACTOR_100P); - scale_factors.push_back(ui::SCALE_FACTOR_200P); - return scale_factors; +std::vector<float> Get1xAnd2xScales() { + std::vector<float> scales; + scales.push_back(1.0f); + scales.push_back(2.0f); + return scales; } const SkBitmap CreateBitmap(int width, int height) { @@ -89,10 +89,9 @@ bool IsEqual(const gfx::Image& img1, const gfx::Image& img2) { return false; for (size_t i = 0; i < img1_reps.size(); ++i) { - ui::ScaleFactor scale_factor = img1_reps[i].scale_factor(); - const gfx::ImageSkiaRep& image_rep2 = image_skia2.GetRepresentation( - scale_factor); - if (image_rep2.scale_factor() != scale_factor || + float scale = img1_reps[i].scale(); + const gfx::ImageSkiaRep& image_rep2 = image_skia2.GetRepresentation(scale); + if (image_rep2.scale() != scale || !IsEqual(img1_reps[i].sk_bitmap(), image_rep2.sk_bitmap())) { return false; } @@ -150,24 +149,22 @@ bool ImageSkiaStructureMatches( const gfx::ImageSkia& image_skia, int width, int height, - const std::vector<ui::ScaleFactor>& scale_factors) { + const std::vector<float>& scales) { if (image_skia.isNull() || image_skia.width() != width || image_skia.height() != height || - image_skia.image_reps().size() != scale_factors.size()) { + image_skia.image_reps().size() != scales.size()) { return false; } - for (size_t i = 0; i < scale_factors.size(); ++i) { + for (size_t i = 0; i < scales.size(); ++i) { gfx::ImageSkiaRep image_rep = - image_skia.GetRepresentation(scale_factors[i]); - if (image_rep.is_null() || - image_rep.scale_factor() != scale_factors[i]) + image_skia.GetRepresentation(scales[i]); + if (image_rep.is_null() || image_rep.scale() != scales[i]) return false; - float scale = ui::GetScaleFactorScale(scale_factors[i]); - if (image_rep.pixel_width() != static_cast<int>(width * scale) || - image_rep.pixel_height() != static_cast<int>(height * scale)) { + if (image_rep.pixel_width() != static_cast<int>(width * scales[i]) || + image_rep.pixel_height() != static_cast<int>(height * scales[i])) { return false; } } @@ -183,8 +180,7 @@ bool IsEmpty(const gfx::Image& image) { PlatformImage CreatePlatformImage() { const SkBitmap bitmap(CreateBitmap(25, 25)); #if defined(OS_IOS) - ui::ScaleFactor scale_factor = ui::GetMaxScaleFactor(); - float scale = ui::GetScaleFactorScale(scale_factor); + float scale = ImageSkia::GetMaxSupportedScale(); base::ScopedCFTypeRef<CGColorSpaceRef> color_space( CGColorSpaceCreateDeviceRGB()); diff --git a/chromium/ui/gfx/image/image_unittest_util.h b/chromium/ui/gfx/image/image_unittest_util.h index a2293c8688b..4788e4e1009 100644 --- a/chromium/ui/gfx/image/image_unittest_util.h +++ b/chromium/ui/gfx/image/image_unittest_util.h @@ -8,7 +8,6 @@ #ifndef UI_GFX_IMAGE_IMAGE_UNITTEST_UTIL_H_ #define UI_GFX_IMAGE_IMAGE_UNITTEST_UTIL_H_ -#include "ui/base/layout.h" #include "ui/gfx/image/image.h" #include "third_party/skia/include/core/SkColor.h" @@ -25,7 +24,7 @@ typedef GdkPixbuf* PlatformImage; typedef gfx::ImageSkia PlatformImage; #endif -std::vector<ui::ScaleFactor> Get1xAnd2xScaleFactors(); +std::vector<float> Get1xAnd2xScales(); // Create a bitmap of |width|x|height|. const SkBitmap CreateBitmap(int width, int height); @@ -65,7 +64,7 @@ bool ImageSkiaStructureMatches( const gfx::ImageSkia& image_skia, int width, int height, - const std::vector<ui::ScaleFactor>& scale_factors); + const std::vector<float>& scale_factors); bool IsEmpty(const gfx::Image& image); diff --git a/chromium/ui/gfx/image/image_util.cc b/chromium/ui/gfx/image/image_util.cc index e230a0b1264..59d631d171d 100644 --- a/chromium/ui/gfx/image/image_util.cc +++ b/chromium/ui/gfx/image/image_util.cc @@ -26,8 +26,8 @@ Image ImageFrom1xJPEGEncodedData(const unsigned char* input, bool JPEG1xEncodedDataFromImage(const Image& image, int quality, std::vector<unsigned char>* dst) { const gfx::ImageSkiaRep& image_skia_rep = - image.AsImageSkia().GetRepresentation(ui::SCALE_FACTOR_100P); - if (image_skia_rep.scale_factor() != ui::SCALE_FACTOR_100P) + image.AsImageSkia().GetRepresentation(1.0f); + if (image_skia_rep.scale() != 1.0f) return false; const SkBitmap& bitmap = image_skia_rep.sk_bitmap(); diff --git a/chromium/ui/gfx/image/image_util.h b/chromium/ui/gfx/image/image_util.h index a039557a8f0..f33835ca232 100644 --- a/chromium/ui/gfx/image/image_util.h +++ b/chromium/ui/gfx/image/image_util.h @@ -18,8 +18,8 @@ namespace gfx { // Creates an image from the given JPEG-encoded input. If there was an error // creating the image, returns an IsEmpty() Image. -UI_EXPORT Image ImageFrom1xJPEGEncodedData(const unsigned char* input, - size_t input_size); +GFX_EXPORT Image ImageFrom1xJPEGEncodedData(const unsigned char* input, + size_t input_size); // Fills the |dst| vector with JPEG-encoded bytes of the 1x representation of // the given image. @@ -27,9 +27,9 @@ UI_EXPORT Image ImageFrom1xJPEGEncodedData(const unsigned char* input, // was encoded successfully. // |quality| determines the compression level, 0 == lowest, 100 == highest. // Returns true if the Image was encoded successfully. -UI_EXPORT bool JPEG1xEncodedDataFromImage(const Image& image, - int quality, - std::vector<unsigned char>* dst); +GFX_EXPORT bool JPEG1xEncodedDataFromImage(const Image& image, + int quality, + std::vector<unsigned char>* dst); } // namespace gfx diff --git a/chromium/ui/gfx/insets.h b/chromium/ui/gfx/insets.h index 571751d937e..a419059a55d 100644 --- a/chromium/ui/gfx/insets.h +++ b/chromium/ui/gfx/insets.h @@ -18,7 +18,7 @@ typedef struct _GtkBorder GtkBorder; namespace gfx { // An integer version of gfx::Insets. -class UI_EXPORT Insets : public InsetsBase<Insets, int> { +class GFX_EXPORT Insets : public InsetsBase<Insets, int> { public: Insets(); Insets(int top, int left, int bottom, int right); diff --git a/chromium/ui/gfx/insets_base.h b/chromium/ui/gfx/insets_base.h index ab105bccfb8..da7aca103e5 100644 --- a/chromium/ui/gfx/insets_base.h +++ b/chromium/ui/gfx/insets_base.h @@ -12,7 +12,7 @@ namespace gfx { // An insets represents the borders of a container (the space the container must // leave at each of its edges). template<typename Class, typename Type> -class UI_EXPORT InsetsBase { +class GFX_EXPORT InsetsBase { public: Type top() const { return top_; } Type left() const { return left_; } diff --git a/chromium/ui/gfx/insets_f.h b/chromium/ui/gfx/insets_f.h index 045b8a02e8e..43b801dcb22 100644 --- a/chromium/ui/gfx/insets_f.h +++ b/chromium/ui/gfx/insets_f.h @@ -14,7 +14,7 @@ namespace gfx { // A floating versin of gfx::Insets. -class UI_EXPORT InsetsF : public InsetsBase<InsetsF, float> { +class GFX_EXPORT InsetsF : public InsetsBase<InsetsF, float> { public: InsetsF(); InsetsF(float top, float left, float bottom, float right); diff --git a/chromium/ui/gfx/interpolated_transform.cc b/chromium/ui/gfx/interpolated_transform.cc index b9698b160cd..4c807f1b4ed 100644 --- a/chromium/ui/gfx/interpolated_transform.cc +++ b/chromium/ui/gfx/interpolated_transform.cc @@ -22,10 +22,6 @@ bool IsMultipleOfNinetyDegrees(double degrees) { return remainder < EPSILON || 90.0 - remainder < EPSILON; } -bool IsApproximatelyZero(double value) { - return fabs(value) < EPSILON; -} - // Returns false if |degrees| is not a multiple of ninety degrees or if // |rotation| is NULL. It does not affect |rotation| in this case. Otherwise // *rotation is set to be the appropriate sanitized rotation matrix. That is, @@ -126,7 +122,7 @@ inline float InterpolatedTransform::ValueBetween(float time, float t = (time - start_time_) / (end_time_ - start_time_); return static_cast<float>( - gfx::Tween::ValueBetween(t, start_value, end_value)); + gfx::Tween::DoubleValueBetween(t, start_value, end_value)); } /////////////////////////////////////////////////////////////////////////////// diff --git a/chromium/ui/gfx/interpolated_transform.h b/chromium/ui/gfx/interpolated_transform.h index 474e3a9dc90..dea9ce91fb3 100644 --- a/chromium/ui/gfx/interpolated_transform.h +++ b/chromium/ui/gfx/interpolated_transform.h @@ -25,7 +25,7 @@ namespace ui { // scale from 0.3 to 1 from between times 0.75 and 1. // /////////////////////////////////////////////////////////////////////////////// -class UI_EXPORT InterpolatedTransform { +class GFX_EXPORT InterpolatedTransform { public: InterpolatedTransform(); // The interpolated transform varies only when t in (start_time, end_time). @@ -84,7 +84,7 @@ class UI_EXPORT InterpolatedTransform { // Represents an animated rotation. // /////////////////////////////////////////////////////////////////////////////// -class UI_EXPORT InterpolatedRotation : public InterpolatedTransform { +class GFX_EXPORT InterpolatedRotation : public InterpolatedTransform { public: InterpolatedRotation(float start_degrees, float end_degrees); InterpolatedRotation(float start_degrees, @@ -109,7 +109,7 @@ class UI_EXPORT InterpolatedRotation : public InterpolatedTransform { // Represents an animated rotation. // /////////////////////////////////////////////////////////////////////////////// -class UI_EXPORT InterpolatedAxisAngleRotation : public InterpolatedTransform { +class GFX_EXPORT InterpolatedAxisAngleRotation : public InterpolatedTransform { public: InterpolatedAxisAngleRotation(const gfx::Vector3dF& axis, float start_degrees, @@ -138,7 +138,7 @@ class UI_EXPORT InterpolatedAxisAngleRotation : public InterpolatedTransform { // Represents an animated scale. // /////////////////////////////////////////////////////////////////////////////// -class UI_EXPORT InterpolatedScale : public InterpolatedTransform { +class GFX_EXPORT InterpolatedScale : public InterpolatedTransform { public: InterpolatedScale(float start_scale, float end_scale); InterpolatedScale(float start_scale, float end_scale, @@ -161,7 +161,7 @@ class UI_EXPORT InterpolatedScale : public InterpolatedTransform { DISALLOW_COPY_AND_ASSIGN(InterpolatedScale); }; -class UI_EXPORT InterpolatedTranslation : public InterpolatedTransform { +class GFX_EXPORT InterpolatedTranslation : public InterpolatedTransform { public: InterpolatedTranslation(const gfx::Point& start_pos, const gfx::Point& end_pos); @@ -190,7 +190,7 @@ class UI_EXPORT InterpolatedTranslation : public InterpolatedTransform { // See InterpolatedTransformAboutPivot for an example of its usage. // /////////////////////////////////////////////////////////////////////////////// -class UI_EXPORT InterpolatedConstantTransform : public InterpolatedTransform { +class GFX_EXPORT InterpolatedConstantTransform : public InterpolatedTransform { public: explicit InterpolatedConstantTransform(const gfx::Transform& transform); virtual ~InterpolatedConstantTransform(); @@ -212,7 +212,8 @@ class UI_EXPORT InterpolatedConstantTransform : public InterpolatedTransform { // P * T * P^-1 where P is a constant transform to the new origin. // /////////////////////////////////////////////////////////////////////////////// -class UI_EXPORT InterpolatedTransformAboutPivot : public InterpolatedTransform { +class GFX_EXPORT InterpolatedTransformAboutPivot + : public InterpolatedTransform { public: // Takes ownership of the passed transform. InterpolatedTransformAboutPivot(const gfx::Point& pivot, @@ -236,7 +237,7 @@ class UI_EXPORT InterpolatedTransformAboutPivot : public InterpolatedTransform { DISALLOW_COPY_AND_ASSIGN(InterpolatedTransformAboutPivot); }; -class UI_EXPORT InterpolatedMatrixTransform : public InterpolatedTransform { +class GFX_EXPORT InterpolatedMatrixTransform : public InterpolatedTransform { public: InterpolatedMatrixTransform(const gfx::Transform& start_transform, const gfx::Transform& end_transform); diff --git a/chromium/ui/gfx/interpolated_transform_unittest.cc b/chromium/ui/gfx/interpolated_transform_unittest.cc index acea465d59a..5215a8b07fe 100644 --- a/chromium/ui/gfx/interpolated_transform_unittest.cc +++ b/chromium/ui/gfx/interpolated_transform_unittest.cc @@ -19,16 +19,6 @@ void CheckApproximatelyEqual(const gfx::Transform& lhs, } } -float NormalizeAngle(float angle) { - while (angle < 0.0f) { - angle += 360.0f; - } - while (angle > 360.0f) { - angle -= 360.0f; - } - return angle; -} - } // namespace TEST(InterpolatedTransformTest, InterpolatedRotation) { diff --git a/chromium/ui/gfx/matrix3_f.h b/chromium/ui/gfx/matrix3_f.h index 83f9cd96cf8..a8ae5b578a8 100644 --- a/chromium/ui/gfx/matrix3_f.h +++ b/chromium/ui/gfx/matrix3_f.h @@ -10,7 +10,7 @@ namespace gfx { -class UI_EXPORT Matrix3F { +class GFX_EXPORT Matrix3F { public: ~Matrix3F(); diff --git a/chromium/ui/gfx/native_widget_types.h b/chromium/ui/gfx/native_widget_types.h index 3d7b9d1cd3b..bd14ed50f77 100644 --- a/chromium/ui/gfx/native_widget_types.h +++ b/chromium/ui/gfx/native_widget_types.h @@ -171,12 +171,12 @@ typedef PangoFontDescription* NativeFont; typedef GtkWidget* NativeEditView; typedef cairo_t* NativeDrawingContext; typedef void* NativeViewAccessible; -#elif defined(USE_AURA) +#elif defined(USE_CAIRO) typedef PangoFontDescription* NativeFont; typedef void* NativeEditView; typedef cairo_t* NativeDrawingContext; typedef void* NativeViewAccessible; -#elif defined(OS_ANDROID) +#else typedef void* NativeFont; typedef void* NativeEditView; typedef void* NativeDrawingContext; diff --git a/chromium/ui/gfx/ozone/dri/dri_skbitmap.cc b/chromium/ui/gfx/ozone/dri/dri_skbitmap.cc new file mode 100644 index 00000000000..4fbe0f54d89 --- /dev/null +++ b/chromium/ui/gfx/ozone/dri/dri_skbitmap.cc @@ -0,0 +1,208 @@ +// 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 new file mode 100644 index 00000000000..f5b8f9455fa --- /dev/null +++ b/chromium/ui/gfx/ozone/dri/dri_skbitmap.h @@ -0,0 +1,57 @@ +// 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 new file mode 100644 index 00000000000..c9b6af4b562 --- /dev/null +++ b/chromium/ui/gfx/ozone/dri/dri_surface.cc @@ -0,0 +1,113 @@ +// 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 new file mode 100644 index 00000000000..53258cf8086 --- /dev/null +++ b/chromium/ui/gfx/ozone/dri/dri_surface.h @@ -0,0 +1,168 @@ +// 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 new file mode 100644 index 00000000000..4c201373942 --- /dev/null +++ b/chromium/ui/gfx/ozone/dri/dri_surface_factory.cc @@ -0,0 +1,317 @@ +// 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 new file mode 100644 index 00000000000..616e989e910 --- /dev/null +++ b/chromium/ui/gfx/ozone/dri/dri_surface_factory.h @@ -0,0 +1,75 @@ +// 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 new file mode 100644 index 00000000000..2e70f642f2a --- /dev/null +++ b/chromium/ui/gfx/ozone/dri/dri_surface_factory_unittest.cc @@ -0,0 +1,292 @@ +// 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 new file mode 100644 index 00000000000..754659163a2 --- /dev/null +++ b/chromium/ui/gfx/ozone/dri/dri_surface_unittest.cc @@ -0,0 +1,212 @@ +// 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 new file mode 100644 index 00000000000..b5717e686f1 --- /dev/null +++ b/chromium/ui/gfx/ozone/dri/dri_vsync_provider.cc @@ -0,0 +1,32 @@ +// 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 new file mode 100644 index 00000000000..b6cb6047eb8 --- /dev/null +++ b/chromium/ui/gfx/ozone/dri/dri_vsync_provider.h @@ -0,0 +1,29 @@ +// 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 new file mode 100644 index 00000000000..2b1104b444d --- /dev/null +++ b/chromium/ui/gfx/ozone/dri/dri_wrapper.cc @@ -0,0 +1,93 @@ +// 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 new file mode 100644 index 00000000000..0848132c9ad --- /dev/null +++ b/chromium/ui/gfx/ozone/dri/dri_wrapper.h @@ -0,0 +1,86 @@ +// 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 new file mode 100644 index 00000000000..6accfc00d53 --- /dev/null +++ b/chromium/ui/gfx/ozone/dri/hardware_display_controller.cc @@ -0,0 +1,129 @@ +// 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 new file mode 100644 index 00000000000..cae8a6ba821 --- /dev/null +++ b/chromium/ui/gfx/ozone/dri/hardware_display_controller.h @@ -0,0 +1,190 @@ +// 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 new file mode 100644 index 00000000000..3806b5a157b --- /dev/null +++ b/chromium/ui/gfx/ozone/dri/hardware_display_controller_unittest.cc @@ -0,0 +1,301 @@ +// 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 new file mode 100644 index 00000000000..9d34f7f95a3 --- /dev/null +++ b/chromium/ui/gfx/ozone/impl/file_surface_factory.cc @@ -0,0 +1,96 @@ +// 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 new file mode 100644 index 00000000000..19f1c946a33 --- /dev/null +++ b/chromium/ui/gfx/ozone/impl/file_surface_factory.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_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 index 9be61f42877..ea8e2f1a0b2 100644 --- a/chromium/ui/gfx/ozone/surface_factory_ozone.cc +++ b/chromium/ui/gfx/ozone/surface_factory_ozone.cc @@ -6,6 +6,8 @@ #include <stdlib.h> +#include "base/command_line.h" + namespace gfx { // static @@ -23,7 +25,11 @@ class SurfaceFactoryOzoneStub : public SurfaceFactoryOzone { gfx::AcceleratedWidget w) OVERRIDE { return 0; } - virtual bool LoadEGLGLES2Bindings() OVERRIDE { return true; } + 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 { @@ -42,7 +48,7 @@ SurfaceFactoryOzone::~SurfaceFactoryOzone() { } SurfaceFactoryOzone* SurfaceFactoryOzone::GetInstance() { - CHECK(impl_) << "SurfaceFactoryOzone accessed before constructed"; + CHECK(impl_) << "No SurfaceFactoryOzone implementation set."; return impl_; } @@ -65,10 +71,19 @@ intptr_t SurfaceFactoryOzone::GetNativeDisplay() { return 0; } -bool SurfaceFactoryOzone::SchedulePageFlip(gfx::AcceleratedWidget) { +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; diff --git a/chromium/ui/gfx/ozone/surface_factory_ozone.h b/chromium/ui/gfx/ozone/surface_factory_ozone.h index 9c5eac23b4f..c09a65ff8c7 100644 --- a/chromium/ui/gfx/ozone/surface_factory_ozone.h +++ b/chromium/ui/gfx/ozone/surface_factory_ozone.h @@ -5,22 +5,59 @@ #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(); @@ -46,8 +83,8 @@ class GFX_EXPORT SurfaceFactoryOzone { // This method must be safe to run inside of the sandbox. virtual void ShutdownHardware() = 0; - // Returns the native EGL display. This is generally needed in creating - // EGL windows. + // 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. @@ -61,8 +98,11 @@ class GFX_EXPORT SurfaceFactoryOzone { virtual gfx::AcceleratedWidget RealizeAcceleratedWidget( gfx::AcceleratedWidget w) = 0; - // Sets up GL bindings for the native surface. - virtual bool LoadEGLGLES2Bindings() = 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 @@ -75,6 +115,12 @@ class GFX_EXPORT SurfaceFactoryOzone { // 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 @@ -82,6 +128,13 @@ class GFX_EXPORT SurfaceFactoryOzone { // 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(); diff --git a/chromium/ui/gfx/pango_util.cc b/chromium/ui/gfx/pango_util.cc index 10bd2538742..1f8ac261b59 100644 --- a/chromium/ui/gfx/pango_util.cc +++ b/chromium/ui/gfx/pango_util.cc @@ -136,40 +136,6 @@ double GetPangoResolution() { return resolution; } -void DrawTextOntoCairoSurface(cairo_t* cr, - const base::string16& text, - const gfx::Font& font, - const gfx::Rect& bounds, - const gfx::Rect& clip, - SkColor text_color, - int flags) { - PangoLayout* layout = pango_cairo_create_layout(cr); - base::i18n::TextDirection text_direction = - base::i18n::GetFirstStrongCharacterDirection(text); - DCHECK(!bounds.IsEmpty()); - - gfx::SetupPangoLayout( - layout, text, font, bounds.width(), text_direction, flags); - - pango_layout_set_height(layout, bounds.height() * PANGO_SCALE); - - cairo_save(cr); - cairo_rectangle(cr, clip.x(), clip.y(), clip.width(), clip.height()); - cairo_clip(cr); - - int width = 0, height = 0; - pango_layout_get_pixel_size(layout, &width, &height); - Rect text_rect(bounds.x(), bounds.y(), width, height); - // Vertically center |text_rect| in |bounds|. - text_rect += gfx::Vector2d(0, (bounds.height() - text_rect.height()) / 2); - - DrawPangoLayout(cr, layout, font, bounds, text_rect, - text_color, text_direction, flags); - - cairo_restore(cr); - g_object_unref(layout); -} - // Pass a width greater than 0 to force wrapping and eliding. static void SetupPangoLayoutWithoutFont( PangoLayout* layout, @@ -260,7 +226,8 @@ static void SetupPangoLayoutWithoutFont( if (flags & Canvas::HIDE_PREFIX) { DCHECK_EQ(1, g_unichar_to_utf8(kAcceleratorChar, NULL)); base::string16 accelerator_removed = - RemoveAcceleratorChar(text, static_cast<char16>(kAcceleratorChar), + RemoveAcceleratorChar(text, + static_cast<base::char16>(kAcceleratorChar), NULL, NULL); utf8 = UTF16ToUTF8(accelerator_removed); } else { @@ -297,60 +264,6 @@ void SetupPangoLayoutWithFontDescription( pango_layout_set_font_description(layout, desc.get()); } -void DrawPangoLayout(cairo_t* cr, - PangoLayout* layout, - const Font& font, - const gfx::Rect& bounds, - const gfx::Rect& text_rect, - SkColor text_color, - base::i18n::TextDirection text_direction, - int flags) { - double r = SkColorGetR(text_color) / 255.0, - g = SkColorGetG(text_color) / 255.0, - b = SkColorGetB(text_color) / 255.0, - a = SkColorGetA(text_color) / 255.0; - - cairo_pattern_t* pattern = NULL; - - cairo_save(cr); - - // Use a fixed color. - // Note: We do not elide (fade out the text) here, due to a bug in certain - // Linux environments (http://crbug.com/123104). - cairo_set_source_rgba(cr, r, g, b, a); - cairo_move_to(cr, text_rect.x(), text_rect.y()); - pango_cairo_show_layout(cr, layout); - - if (font.GetStyle() & gfx::Font::UNDERLINE) { - gfx::PlatformFontPango* platform_font = - static_cast<gfx::PlatformFontPango*>(font.platform_font()); - DrawPangoTextUnderline(cr, platform_font, 0.0, text_rect); - } - - if (pattern) - cairo_pattern_destroy(pattern); - - cairo_restore(cr); -} - -void DrawPangoTextUnderline(cairo_t* cr, - gfx::PlatformFontPango* platform_font, - double extra_edge_width, - const Rect& text_rect) { - const double underline_y = - static_cast<double>(text_rect.y()) + text_rect.height() + - platform_font->underline_position(); - cairo_set_line_width( - cr, platform_font->underline_thickness() + 2 * extra_edge_width); - cairo_move_to(cr, - text_rect.x() - extra_edge_width, - underline_y); - cairo_line_to(cr, - text_rect.x() + text_rect.width() + extra_edge_width, - underline_y); - cairo_stroke(cr); -} - size_t GetPangoFontSizeInPixels(PangoFontDescription* pango_font) { size_t size_in_pixels = pango_font_description_get_size(pango_font); if (pango_font_description_get_size_is_absolute(pango_font)) { diff --git a/chromium/ui/gfx/pango_util.h b/chromium/ui/gfx/pango_util.h index 840163825cd..db60c2e6d58 100644 --- a/chromium/ui/gfx/pango_util.h +++ b/chromium/ui/gfx/pango_util.h @@ -50,32 +50,14 @@ class ScopedPangoFontDescription { DISALLOW_COPY_AND_ASSIGN(ScopedPangoFontDescription); }; -// Uses Pango to draw text onto |cr|. This is the public method for d -void UI_EXPORT DrawTextOntoCairoSurface(cairo_t* cr, - const base::string16& text, - const gfx::Font& font, - const gfx::Rect& bounds, - const gfx::Rect& clip, - SkColor text_color, - int flags); - // ---------------------------------------------------------------------------- // All other methods in this file are only to be used within the ui/ directory. // They are shared with internal skia interfaces. // ---------------------------------------------------------------------------- -// Setup pango |layout|; set the |text|, the font description based on |font|, -// the |width| in PANGO_SCALE for RTL locale, the base |text_direction|, -// alignment, ellipsis, word wrapping, resolution, etc. -void SetupPangoLayout(PangoLayout* layout, - const base::string16& text, - const gfx::Font& font, - int width, - base::i18n::TextDirection text_direction, - int flags); - -// Setup pango layout |layout| the same way as SetupPangoLayout(), except this -// sets the font description based on |font_description|. +// Setup pango |layout|; set the |text|, the font description based on +// |font_description|, the |width| in PANGO_SCALE for RTL locale, the base +// |text_direction|, alignment, ellipsis, word wrapping, resolution, etc. void SetupPangoLayoutWithFontDescription( PangoLayout* layout, const base::string16& text, @@ -84,25 +66,6 @@ void SetupPangoLayoutWithFontDescription( base::i18n::TextDirection text_direction, int flags); -// Draws the |layout| (pango tuple of font, actual text, etc) onto |cr| using -// |text_color| as the cairo pattern. -void DrawPangoLayout(cairo_t* cr, - PangoLayout* layout, - const Font& font, - const gfx::Rect& bounds, - const gfx::Rect& text_rect, - SkColor text_color, - base::i18n::TextDirection text_direction, - int flags); - -// Draw an underline under the text using |cr|, which must already be -// initialized with the correct source. |extra_edge_width| is added to the -// outer edge of the line. -void DrawPangoTextUnderline(cairo_t* cr, - gfx::PlatformFontPango* platform_font, - double extra_edge_width, - const Rect& text_rect); - // Returns the size in pixels for the specified |pango_font|. size_t GetPangoFontSizeInPixels(PangoFontDescription* pango_font); diff --git a/chromium/ui/gfx/path.h b/chromium/ui/gfx/path.h index f1c7718f9a3..257a65c0102 100644 --- a/chromium/ui/gfx/path.h +++ b/chromium/ui/gfx/path.h @@ -12,7 +12,7 @@ namespace gfx { -class UI_EXPORT Path : public SkPath { +class GFX_EXPORT Path : public SkPath { public: // Used by Path(Point,size_t) constructor. struct Point { diff --git a/chromium/ui/gfx/path_win.cc b/chromium/ui/gfx/path_win.cc index be5d9e22ecb..bce62ac849b 100644 --- a/chromium/ui/gfx/path_win.cc +++ b/chromium/ui/gfx/path_win.cc @@ -5,10 +5,25 @@ #include "ui/gfx/path_win.h" #include "base/memory/scoped_ptr.h" +#include "base/win/scoped_gdi_object.h" +#include "third_party/skia/include/core/SkRegion.h" #include "ui/gfx/path.h" namespace gfx { +HRGN CreateHRGNFromSkRegion(const SkRegion& region) { + base::win::ScopedRegion temp(::CreateRectRgn(0, 0, 0, 0)); + base::win::ScopedRegion result(::CreateRectRgn(0, 0, 0, 0)); + + for (SkRegion::Iterator i(region); !i.done(); i.next()) { + const SkIRect& rect = i.rect(); + ::SetRectRgn(temp, rect.left(), rect.top(), rect.right(), rect.bottom()); + ::CombineRgn(result, result, temp, RGN_OR); + } + + return result.release(); +} + HRGN CreateHRGNFromSkPath(const SkPath& path) { int point_count = path.getPoints(NULL, 0); scoped_ptr<SkPoint[]> points(new SkPoint[point_count]); diff --git a/chromium/ui/gfx/path_win.h b/chromium/ui/gfx/path_win.h index f64bc80a5ef..317a6fb0700 100644 --- a/chromium/ui/gfx/path_win.h +++ b/chromium/ui/gfx/path_win.h @@ -10,12 +10,17 @@ #include "ui/gfx/gfx_export.h" class SkPath; +class SkRegion; namespace gfx { +// Creates a new HRGN given |region|. The caller is responsible for destroying +// the returned region. +GFX_EXPORT HRGN CreateHRGNFromSkRegion(const SkRegion& path); + // Creates a new HRGN given |path|. The caller is responsible for destroying // the returned region. -UI_EXPORT HRGN CreateHRGNFromSkPath(const SkPath& path); +GFX_EXPORT HRGN CreateHRGNFromSkPath(const SkPath& path); } // namespace gfx diff --git a/chromium/ui/gfx/path_x11.cc b/chromium/ui/gfx/path_x11.cc index 2cfd10abe34..2fe764fbd4c 100644 --- a/chromium/ui/gfx/path_x11.cc +++ b/chromium/ui/gfx/path_x11.cc @@ -7,10 +7,26 @@ #include <X11/Xutil.h> #include "base/memory/scoped_ptr.h" +#include "third_party/skia/include/core/SkRegion.h" #include "ui/gfx/path.h" namespace gfx { +Region CreateRegionFromSkRegion(const SkRegion& region) { + Region result = XCreateRegion(); + + for (SkRegion::Iterator i(region); !i.done(); i.next()) { + XRectangle rect; + rect.x = i.rect().x(); + rect.y = i.rect().y(); + rect.width = i.rect().width(); + rect.height = i.rect().height(); + XUnionRectWithRegion(&rect, result, result); + } + + return result; +} + Region CreateRegionFromSkPath(const SkPath& path) { int point_count = path.getPoints(NULL, 0); scoped_ptr<SkPoint[]> points(new SkPoint[point_count]); diff --git a/chromium/ui/gfx/path_x11.h b/chromium/ui/gfx/path_x11.h index e5a309209cc..c6e750742ec 100644 --- a/chromium/ui/gfx/path_x11.h +++ b/chromium/ui/gfx/path_x11.h @@ -11,12 +11,17 @@ #include "ui/gfx/gfx_export.h" class SkPath; +class SkRegion; namespace gfx { +// Creates a new REGION given |region|. The caller is responsible for destroying +// the returned region. +GFX_EXPORT REGION* CreateRegionFromSkRegion(const SkRegion& region); + // Creates a new REGION given |path|. The caller is responsible for destroying // the returned region. -UI_EXPORT REGION* CreateRegionFromSkPath(const SkPath& path); +GFX_EXPORT REGION* CreateRegionFromSkPath(const SkPath& path); } // namespace gfx diff --git a/chromium/ui/gfx/platform_font.h b/chromium/ui/gfx/platform_font.h index 09bf8be0b3d..bf470983e12 100644 --- a/chromium/ui/gfx/platform_font.h +++ b/chromium/ui/gfx/platform_font.h @@ -16,7 +16,7 @@ namespace gfx { class Font; -class UI_EXPORT PlatformFont : public base::RefCounted<PlatformFont> { +class GFX_EXPORT PlatformFont : public base::RefCounted<PlatformFont> { public: // Creates an appropriate PlatformFont implementation. static PlatformFont* CreateDefault(); @@ -42,6 +42,9 @@ class UI_EXPORT PlatformFont : public base::RefCounted<PlatformFont> { // Returns the baseline, or ascent, of the font. virtual int GetBaseline() const = 0; + // 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; @@ -57,9 +60,12 @@ class UI_EXPORT PlatformFont : public base::RefCounted<PlatformFont> { // Returns the style of the font. virtual int GetStyle() const = 0; - // Returns the font name in UTF-8. + // Returns the specified font name in UTF-8. virtual std::string GetFontName() const = 0; + // Returns the actually used font name in UTF-8. + virtual std::string GetActualFontNameForTesting() const = 0; + // Returns the font size in pixels. virtual int GetFontSize() const = 0; @@ -76,4 +82,3 @@ class UI_EXPORT PlatformFont : public base::RefCounted<PlatformFont> { } // namespace gfx #endif // UI_GFX_PLATFORM_FONT_H_ - diff --git a/chromium/ui/gfx/platform_font_ios.h b/chromium/ui/gfx/platform_font_ios.h index 789b591415d..ed93a6b6e66 100644 --- a/chromium/ui/gfx/platform_font_ios.h +++ b/chromium/ui/gfx/platform_font_ios.h @@ -20,11 +20,13 @@ class PlatformFontIOS : public PlatformFont { virtual Font DeriveFont(int size_delta, int style) const OVERRIDE; 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; + virtual std::string GetActualFontNameForTesting() const OVERRIDE; virtual int GetFontSize() const OVERRIDE; virtual NativeFont GetNativeFont() const OVERRIDE; @@ -47,6 +49,7 @@ class PlatformFontIOS : public PlatformFont { // Cached metrics, generated at construction. int height_; int ascent_; + int cap_height_; int average_width_; DISALLOW_COPY_AND_ASSIGN(PlatformFontIOS); diff --git a/chromium/ui/gfx/platform_font_ios.mm b/chromium/ui/gfx/platform_font_ios.mm index cfc69cf4964..32dcca4e395 100644 --- a/chromium/ui/gfx/platform_font_ios.mm +++ b/chromium/ui/gfx/platform_font_ios.mm @@ -51,6 +51,10 @@ int PlatformFontIOS::GetBaseline() const { return ascent_; } +int PlatformFontIOS::GetCapHeight() const { + return cap_height_; +} + int PlatformFontIOS::GetAverageCharacterWidth() const { return average_width_; } @@ -72,6 +76,10 @@ std::string PlatformFontIOS::GetFontName() const { return font_name_; } +std::string PlatformFontIOS::GetActualFontNameForTesting() const { + return base::SysNSStringToUTF8([GetNativeFont() familyName]); +} + int PlatformFontIOS::GetFontSize() const { return font_size_; } @@ -103,6 +111,7 @@ void PlatformFontIOS::CalculateMetrics() { UIFont* font = GetNativeFont(); height_ = font.lineHeight; ascent_ = font.ascender; + cap_height_ = font.capHeight; average_width_ = [@"x" sizeWithFont:font].width; } diff --git a/chromium/ui/gfx/platform_font_mac.h b/chromium/ui/gfx/platform_font_mac.h index 13c8677c228..2f5f8deb3fe 100644 --- a/chromium/ui/gfx/platform_font_mac.h +++ b/chromium/ui/gfx/platform_font_mac.h @@ -6,6 +6,7 @@ #define UI_GFX_PLATFORM_FONT_MAC_H_ #include "base/compiler_specific.h" +#include "base/mac/scoped_nsobject.h" #include "ui/gfx/platform_font.h" namespace gfx { @@ -21,33 +22,39 @@ class PlatformFontMac : public PlatformFont { virtual Font DeriveFont(int size_delta, int style) const OVERRIDE; 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; + virtual std::string GetActualFontNameForTesting() const OVERRIDE; virtual int GetFontSize() const OVERRIDE; virtual NativeFont GetNativeFont() const OVERRIDE; private: - PlatformFontMac(const std::string& font_name, int font_size, int style); - virtual ~PlatformFontMac() {} + PlatformFontMac(const std::string& font_name, int font_size, int font_style); + virtual ~PlatformFontMac(); - // Initialize the object with the specified parameters. - void InitWithNameSizeAndStyle(const std::string& font_name, - int font_size, - int style); - - // Calculate and cache the font metrics. + // Calculates and caches the font metrics. void CalculateMetrics(); - std::string font_name_; + // The NSFont instance for this object. If this object was constructed from an + // NSFont instance, this holds that NSFont instance. Otherwise this NSFont + // instance is constructed from the name, size, and style, and if there is no + // active font that matched those criteria, this object may be nil. + base::scoped_nsobject<NSFont> native_font_; + + // The name/size/style trio that specify the font. Initialized in the + // constructors. + std::string font_name_; // Corresponds to -[NSFont fontFamily]. int font_size_; - int style_; + int font_style_; - // Cached metrics, generated at construction. + // Cached metrics, generated in CalculateMetrics(). int height_; int ascent_; + int cap_height_; int average_width_; DISALLOW_COPY_AND_ASSIGN(PlatformFontMac); diff --git a/chromium/ui/gfx/platform_font_mac.mm b/chromium/ui/gfx/platform_font_mac.mm index bf0c0bd54ac..877507eb47b 100644 --- a/chromium/ui/gfx/platform_font_mac.mm +++ b/chromium/ui/gfx/platform_font_mac.mm @@ -15,33 +15,75 @@ namespace gfx { +namespace { + +// Returns an autoreleased NSFont created with the passed-in specifications. +NSFont* NSFontWithSpec(const std::string& font_name, + int font_size, + int font_style) { + NSFontSymbolicTraits trait_bits = 0; + if (font_style & Font::BOLD) + trait_bits |= NSFontBoldTrait; + if (font_style & Font::ITALIC) + trait_bits |= NSFontItalicTrait; + // The Mac doesn't support underline as a font trait, so just drop it. + // (Underlines must be added as an attribute on an NSAttributedString.) + NSDictionary* traits = @{ NSFontSymbolicTrait : @(trait_bits) }; + + NSDictionary* attrs = @{ + NSFontFamilyAttribute : base::SysUTF8ToNSString(font_name), + NSFontTraitsAttribute : traits + }; + NSFontDescriptor* descriptor = + [NSFontDescriptor fontDescriptorWithFontAttributes:attrs]; + NSFont* font = [NSFont fontWithDescriptor:descriptor size:font_size]; + if (font) + return font; + + // Make one fallback attempt by looking up via font name rather than font + // family name. + attrs = @{ + NSFontNameAttribute : base::SysUTF8ToNSString(font_name), + NSFontTraitsAttribute : traits + }; + descriptor = [NSFontDescriptor fontDescriptorWithFontAttributes:attrs]; + return [NSFont fontWithDescriptor:descriptor size:font_size]; +} + +} // namespace + //////////////////////////////////////////////////////////////////////////////// // PlatformFontMac, public: -PlatformFontMac::PlatformFontMac() { - font_size_ = [NSFont systemFontSize]; - style_ = gfx::Font::NORMAL; - NSFont* system_font = [NSFont systemFontOfSize:font_size_]; - font_name_ = base::SysNSStringToUTF8([system_font fontName]); +PlatformFontMac::PlatformFontMac() + : native_font_([[NSFont systemFontOfSize:[NSFont systemFontSize]] retain]), + font_name_(base::SysNSStringToUTF8([native_font_ familyName])), + font_size_([NSFont systemFontSize]), + font_style_(Font::NORMAL) { CalculateMetrics(); } -PlatformFontMac::PlatformFontMac(NativeFont native_font) { - int style = 0; +PlatformFontMac::PlatformFontMac(NativeFont native_font) + : native_font_([native_font retain]), + font_name_(base::SysNSStringToUTF8([native_font_ familyName])), + font_size_([native_font_ pointSize]), + font_style_(Font::NORMAL) { NSFontSymbolicTraits traits = [[native_font fontDescriptor] symbolicTraits]; if (traits & NSFontItalicTrait) - style |= Font::ITALIC; + font_style_ |= Font::ITALIC; if (traits & NSFontBoldTrait) - style |= Font::BOLD; + font_style_ |= Font::BOLD; - InitWithNameSizeAndStyle(base::SysNSStringToUTF8([native_font familyName]), - [native_font pointSize], - style); + CalculateMetrics(); } PlatformFontMac::PlatformFontMac(const std::string& font_name, - int font_size) { - InitWithNameSizeAndStyle(font_name, font_size, gfx::Font::NORMAL); + int font_size) + : native_font_([NSFontWithSpec(font_name, font_size, Font::NORMAL) retain]), + font_name_(font_name), + font_size_(font_size), + font_style_(Font::NORMAL) { + CalculateMetrics(); } //////////////////////////////////////////////////////////////////////////////// @@ -59,6 +101,10 @@ int PlatformFontMac::GetBaseline() const { return ascent_; } +int PlatformFontMac::GetCapHeight() const { + return cap_height_; +} + int PlatformFontMac::GetAverageCharacterWidth() const { return average_width_; } @@ -73,35 +119,23 @@ int PlatformFontMac::GetExpectedTextWidth(int length) const { } int PlatformFontMac::GetStyle() const { - return style_; + return font_style_; } std::string PlatformFontMac::GetFontName() const { return font_name_; } +std::string PlatformFontMac::GetActualFontNameForTesting() const { + return base::SysNSStringToUTF8([native_font_ familyName]); +} + int PlatformFontMac::GetFontSize() const { return font_size_; } NativeFont PlatformFontMac::GetNativeFont() const { - // We could cache this, but then we'd have to conditionally change the - // dtor just for MacOS. Not sure if we want to/need to do that. - NSFont* font = [NSFont fontWithName:base::SysUTF8ToNSString(font_name_) - size:font_size_]; - - if (style_ & Font::BOLD) { - font = [[NSFontManager sharedFontManager] convertFont:font - toHaveTrait:NSBoldFontMask]; - } - if (style_ & Font::ITALIC) { - font = [[NSFontManager sharedFontManager] convertFont:font - toHaveTrait:NSItalicFontMask]; - } - // Mac doesn't support underline as a font trait, just drop it. Underlines - // can instead be added as an attribute on an NSAttributedString. - - return font; + return [[native_font_.get() retain] autorelease]; } //////////////////////////////////////////////////////////////////////////////// @@ -109,25 +143,34 @@ NativeFont PlatformFontMac::GetNativeFont() const { PlatformFontMac::PlatformFontMac(const std::string& font_name, int font_size, - int style) { - InitWithNameSizeAndStyle(font_name, font_size, style); + int font_style) + : native_font_([NSFontWithSpec(font_name, font_size, font_style) retain]), + font_name_(font_name), + font_size_(font_size), + font_style_(font_style) { + CalculateMetrics(); } -void PlatformFontMac::InitWithNameSizeAndStyle(const std::string& font_name, - int font_size, - int style) { - font_name_ = font_name; - font_size_ = font_size; - style_ = style; - CalculateMetrics(); +PlatformFontMac::~PlatformFontMac() { } void PlatformFontMac::CalculateMetrics() { - NSFont* font = GetNativeFont(); + NSFont* font = native_font_.get(); + if (!font) { + // This object was constructed from a font name that doesn't correspond to + // an actual font. Don't waste time working out metrics. + height_ = 0; + ascent_ = 0; + cap_height_ = 0; + average_width_ = 0; + return; + } + base::scoped_nsobject<NSLayoutManager> layout_manager( [[NSLayoutManager alloc] init]); height_ = [layout_manager defaultLineHeightForFont:font]; ascent_ = [font ascender]; + cap_height_ = [font capHeight]; average_width_ = NSWidth([font boundingRectForGlyph:[font glyphWithName:@"x"]]); } @@ -152,4 +195,3 @@ PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string& font_name, } } // namespace gfx - diff --git a/chromium/ui/gfx/platform_font_ozone.cc b/chromium/ui/gfx/platform_font_ozone.cc new file mode 100644 index 00000000000..aef042a0c93 --- /dev/null +++ b/chromium/ui/gfx/platform_font_ozone.cc @@ -0,0 +1,25 @@ +// 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/platform_font.h" + +namespace gfx { + +// static +PlatformFont* PlatformFont::CreateDefault() { + return NULL; +} + +// static +PlatformFont* PlatformFont::CreateFromNativeFont(NativeFont native_font) { + return NULL; +} + +// static +PlatformFont* PlatformFont::CreateFromNameAndSize(const std::string& font_name, + int font_size) { + return NULL; +} + +} // namespace gfx diff --git a/chromium/ui/gfx/platform_font_pango.cc b/chromium/ui/gfx/platform_font_pango.cc index 0ddf363c3f7..db1d7dce351 100644 --- a/chromium/ui/gfx/platform_font_pango.cc +++ b/chromium/ui/gfx/platform_font_pango.cc @@ -15,6 +15,7 @@ #include "base/strings/string_split.h" #include "base/strings/utf_string_conversions.h" #include "third_party/skia/include/core/SkPaint.h" +#include "third_party/skia/include/core/SkString.h" #include "third_party/skia/include/core/SkTypeface.h" #include "ui/gfx/canvas.h" #include "ui/gfx/font.h" @@ -182,6 +183,16 @@ int PlatformFontPango::GetBaseline() const { return ascent_pixels_; } +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_); @@ -205,6 +216,12 @@ std::string PlatformFontPango::GetFontName() const { return font_family_; } +std::string PlatformFontPango::GetActualFontNameForTesting() const { + SkString family_name; + typeface_->getFamilyName(&family_name); + return family_name.c_str(); +} + int PlatformFontPango::GetFontSize() const { return font_size_pixels_; } @@ -283,7 +300,7 @@ void PlatformFontPango::InitWithNameAndSize(const std::string& font_name, std::string fallback; skia::RefPtr<SkTypeface> typeface = skia::AdoptRef( - SkTypeface::CreateFromName(font_name.c_str(), SkTypeface::kNormal)); + SkTypeface::CreateFromName(font_name.c_str(), SkTypeface::kNormal)); if (!typeface) { // A non-scalable font such as .pcf is specified. Falls back to a default // scalable font. @@ -381,7 +398,6 @@ void PlatformFontPango::InitPangoMetrics() { } } - double PlatformFontPango::GetAverageWidth() const { const_cast<PlatformFontPango*>(this)->InitPangoMetrics(); return average_width_pixels_; diff --git a/chromium/ui/gfx/platform_font_pango.h b/chromium/ui/gfx/platform_font_pango.h index 1804f37ddd3..739a633aa47 100644 --- a/chromium/ui/gfx/platform_font_pango.h +++ b/chromium/ui/gfx/platform_font_pango.h @@ -18,7 +18,7 @@ class SkPaint; namespace gfx { -class UI_EXPORT PlatformFontPango : public PlatformFont { +class GFX_EXPORT PlatformFontPango : public PlatformFont { public: PlatformFontPango(); explicit PlatformFontPango(NativeFont native_font); @@ -49,11 +49,13 @@ class UI_EXPORT PlatformFontPango : public PlatformFont { virtual Font DeriveFont(int size_delta, int style) const OVERRIDE; 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; + virtual std::string GetActualFontNameForTesting() const OVERRIDE; virtual int GetFontSize() const OVERRIDE; virtual NativeFont GetNativeFont() const OVERRIDE; @@ -74,8 +76,8 @@ class UI_EXPORT PlatformFontPango : public PlatformFont { void InitWithNameAndSize(const std::string& font_name, int font_size); void InitWithTypefaceNameSizeAndStyle( const skia::RefPtr<SkTypeface>& typeface, - const std::string& name, - int size, + const std::string& font_family, + int font_size, int style); void InitFromPlatformFont(const PlatformFontPango* other); diff --git a/chromium/ui/gfx/platform_font_win.cc b/chromium/ui/gfx/platform_font_win.cc index 2d4c006f268..0209be6673e 100644 --- a/chromium/ui/gfx/platform_font_win.cc +++ b/chromium/ui/gfx/platform_font_win.cc @@ -141,6 +141,10 @@ int PlatformFontWin::GetBaseline() const { return font_ref_->baseline(); } +int PlatformFontWin::GetCapHeight() const { + return font_ref_->cap_height(); +} + int PlatformFontWin::GetAverageCharacterWidth() const { return font_ref_->ave_char_width(); } @@ -163,6 +167,13 @@ std::string PlatformFontWin::GetFontName() const { return font_ref_->font_name(); } +std::string PlatformFontWin::GetActualFontNameForTesting() const { + // With the current implementation on Windows, HFontRef::font_name() returns + // the font name taken from the HFONT handle, but it's not the name that comes + // from the font's metadata. See http://crbug.com/327287 + return font_ref_->font_name(); +} + std::string PlatformFontWin::GetLocalizedFontName() const { base::win::ScopedCreateDC memory_dc(CreateCompatibleDC(NULL)); if (!memory_dc.Get()) @@ -235,6 +246,8 @@ PlatformFontWin::HFontRef* PlatformFontWin::CreateHFontRef(HFONT font) { const int height = std::max<int>(1, font_metrics.tmHeight); const int baseline = std::max<int>(1, font_metrics.tmAscent); + const int cap_height = + std::max<int>(1, font_metrics.tmAscent - font_metrics.tmInternalLeading); const int ave_char_width = std::max<int>(1, font_metrics.tmAveCharWidth); const int font_size = std::max<int>(1, font_metrics.tmHeight - font_metrics.tmInternalLeading); @@ -246,7 +259,8 @@ PlatformFontWin::HFontRef* PlatformFontWin::CreateHFontRef(HFONT font) { if (font_metrics.tmWeight >= kTextMetricWeightBold) style |= Font::BOLD; - return new HFontRef(font, font_size, height, baseline, ave_char_width, style); + return new HFontRef(font, font_size, height, baseline, cap_height, + ave_char_width, style); } PlatformFontWin::PlatformFontWin(HFontRef* hfont_ref) : font_ref_(hfont_ref) { @@ -256,15 +270,17 @@ PlatformFontWin::PlatformFontWin(HFontRef* hfont_ref) : font_ref_(hfont_ref) { // PlatformFontWin::HFontRef: PlatformFontWin::HFontRef::HFontRef(HFONT hfont, - int font_size, - int height, - int baseline, - int ave_char_width, - int style) + int font_size, + int height, + int baseline, + int cap_height, + int ave_char_width, + int style) : hfont_(hfont), font_size_(font_size), height_(height), baseline_(baseline), + cap_height_(cap_height), ave_char_width_(ave_char_width), style_(style), dlu_base_x_(-1), diff --git a/chromium/ui/gfx/platform_font_win.h b/chromium/ui/gfx/platform_font_win.h index ffa82499d45..4826f777ffc 100644 --- a/chromium/ui/gfx/platform_font_win.h +++ b/chromium/ui/gfx/platform_font_win.h @@ -14,7 +14,7 @@ namespace gfx { -class UI_EXPORT PlatformFontWin : public PlatformFont { +class GFX_EXPORT PlatformFontWin : public PlatformFont { public: PlatformFontWin(); explicit PlatformFontWin(NativeFont native_font); @@ -57,11 +57,13 @@ class UI_EXPORT PlatformFontWin : public PlatformFont { virtual Font DeriveFont(int size_delta, int style) const OVERRIDE; 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; + virtual std::string GetActualFontNameForTesting() const OVERRIDE; virtual int GetFontSize() const OVERRIDE; virtual NativeFont GetNativeFont() const OVERRIDE; @@ -84,6 +86,7 @@ class UI_EXPORT PlatformFontWin : public PlatformFont { int font_size, int height, int baseline, + int cap_height, int ave_char_width, int style); @@ -91,6 +94,7 @@ class UI_EXPORT PlatformFontWin : public PlatformFont { HFONT hfont() const { return hfont_; } int height() const { return height_; } int baseline() const { return baseline_; } + int cap_height() const { return cap_height_; } int ave_char_width() const { return ave_char_width_; } int style() const { return style_; } const std::string& font_name() const { return font_name_; } @@ -109,6 +113,7 @@ class UI_EXPORT PlatformFontWin : public PlatformFont { const int font_size_; const int height_; const int baseline_; + const int cap_height_; const int ave_char_width_; const int style_; // Average character width in dialog units. This is queried lazily from the @@ -155,4 +160,3 @@ class UI_EXPORT PlatformFontWin : public PlatformFont { } // namespace gfx #endif // UI_GFX_PLATFORM_FONT_WIN_H_ - diff --git a/chromium/ui/gfx/point.h b/chromium/ui/gfx/point.h index cb233da5274..020c4e1251a 100644 --- a/chromium/ui/gfx/point.h +++ b/chromium/ui/gfx/point.h @@ -22,7 +22,7 @@ typedef struct tagPOINT POINT; namespace gfx { // A point has an x and y coordinate. -class UI_EXPORT Point : public PointBase<Point, int, Vector2d> { +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) {} diff --git a/chromium/ui/gfx/point3_f.h b/chromium/ui/gfx/point3_f.h index 5ea0c3181f0..485f6558136 100644 --- a/chromium/ui/gfx/point3_f.h +++ b/chromium/ui/gfx/point3_f.h @@ -14,7 +14,7 @@ namespace gfx { // A point has an x, y and z coordinate. -class UI_EXPORT Point3F { +class GFX_EXPORT Point3F { public: Point3F() : x_(0), y_(0), z_(0) {} @@ -90,15 +90,15 @@ inline bool operator!=(const Point3F& lhs, const Point3F& rhs) { } // Add a vector to a point, producing a new point offset by the vector. -UI_EXPORT Point3F operator+(const Point3F& lhs, const Vector3dF& rhs); +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. -UI_EXPORT Point3F operator-(const Point3F& lhs, const Vector3dF& rhs); +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. -UI_EXPORT Vector3dF operator-(const Point3F& lhs, const Point3F& rhs); +GFX_EXPORT Vector3dF operator-(const Point3F& lhs, const Point3F& rhs); inline Point3F PointAtOffsetFromOrigin(const Vector3dF& offset) { return Point3F(offset.x(), offset.y(), offset.z()); diff --git a/chromium/ui/gfx/point_base.h b/chromium/ui/gfx/point_base.h index 17f1d5183c4..d7a3951913e 100644 --- a/chromium/ui/gfx/point_base.h +++ b/chromium/ui/gfx/point_base.h @@ -15,7 +15,7 @@ namespace gfx { // A point has an x and y coordinate. template<typename Class, typename Type, typename VectorClass> -class UI_EXPORT PointBase { +class GFX_EXPORT PointBase { public: Type x() const { return x_; } Type y() const { return y_; } diff --git a/chromium/ui/gfx/point_conversions.h b/chromium/ui/gfx/point_conversions.h index 9467a9231dc..942edd711cc 100644 --- a/chromium/ui/gfx/point_conversions.h +++ b/chromium/ui/gfx/point_conversions.h @@ -11,13 +11,13 @@ namespace gfx { // Returns a Point with each component from the input PointF floored. -UI_EXPORT Point ToFlooredPoint(const PointF& point); +GFX_EXPORT Point ToFlooredPoint(const PointF& point); // Returns a Point with each component from the input PointF ceiled. -UI_EXPORT Point ToCeiledPoint(const PointF& point); +GFX_EXPORT Point ToCeiledPoint(const PointF& point); // Returns a Point with each component from the input PointF rounded. -UI_EXPORT Point ToRoundedPoint(const PointF& point); +GFX_EXPORT Point ToRoundedPoint(const PointF& point); } // namespace gfx diff --git a/chromium/ui/gfx/point_f.h b/chromium/ui/gfx/point_f.h index d9fc18cbbcc..664c18d8aa0 100644 --- a/chromium/ui/gfx/point_f.h +++ b/chromium/ui/gfx/point_f.h @@ -14,7 +14,7 @@ namespace gfx { // A floating version of gfx::Point. -class UI_EXPORT PointF : public PointBase<PointF, float, Vector2dF> { +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) {} @@ -60,7 +60,7 @@ inline PointF PointAtOffsetFromOrigin(const Vector2dF& offset_from_origin) { return PointF(offset_from_origin.x(), offset_from_origin.y()); } -UI_EXPORT PointF ScalePoint(const PointF& p, float x_scale, float y_scale); +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); diff --git a/chromium/ui/gfx/quad_f.h b/chromium/ui/gfx/quad_f.h index 5bbc3cd40dd..b8a42e9883e 100644 --- a/chromium/ui/gfx/quad_f.h +++ b/chromium/ui/gfx/quad_f.h @@ -17,7 +17,7 @@ namespace gfx { // A Quad is defined by four corners, allowing it to have edges that are not // axis-aligned, unlike a Rect. -class UI_EXPORT QuadF { +class GFX_EXPORT QuadF { public: QuadF() {} QuadF(const PointF& p1, const PointF& p2, const PointF& p3, const PointF& p4) @@ -99,10 +99,10 @@ inline bool operator!=(const QuadF& lhs, const QuadF& rhs) { } // Add a vector to a quad, offseting each point in the quad by the vector. -UI_EXPORT QuadF operator+(const QuadF& lhs, const Vector2dF& rhs); +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. -UI_EXPORT QuadF operator-(const QuadF& lhs, const Vector2dF& rhs); +GFX_EXPORT QuadF operator-(const QuadF& lhs, const Vector2dF& rhs); } // namespace gfx diff --git a/chromium/ui/gfx/range/range.h b/chromium/ui/gfx/range/range.h index c41c98c8d03..d0d2a3ec954 100644 --- a/chromium/ui/gfx/range/range.h +++ b/chromium/ui/gfx/range/range.h @@ -31,7 +31,7 @@ namespace gfx { // position; when they are the same, the Range is akin to a caret. Note that // |start_| can be greater than |end_| to respect the directionality of the // range. -class UI_EXPORT Range { +class GFX_EXPORT Range { public: // Creates an empty range {0,0}. Range(); @@ -110,7 +110,7 @@ class UI_EXPORT Range { size_t end_; }; -UI_EXPORT std::ostream& operator<<(std::ostream& os, const Range& range); +GFX_EXPORT std::ostream& operator<<(std::ostream& os, const Range& range); } // namespace gfx diff --git a/chromium/ui/gfx/rect.h b/chromium/ui/gfx/rect.h index d983770dca8..df7f9aac366 100644 --- a/chromium/ui/gfx/rect.h +++ b/chromium/ui/gfx/rect.h @@ -35,7 +35,7 @@ namespace gfx { class Insets; -class UI_EXPORT Rect +class GFX_EXPORT Rect : public RectBase<Rect, Point, Size, Insets, Vector2d, int> { public: Rect() : RectBase<Rect, Point, Size, Insets, Vector2d, int>(Point()) {} @@ -89,16 +89,16 @@ inline bool operator!=(const Rect& lhs, const Rect& rhs) { return !(lhs == rhs); } -UI_EXPORT Rect operator+(const Rect& lhs, const Vector2d& rhs); -UI_EXPORT Rect operator-(const Rect& lhs, const Vector2d& 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; } -UI_EXPORT Rect IntersectRects(const Rect& a, const Rect& b); -UI_EXPORT Rect UnionRects(const Rect& a, const Rect& b); -UI_EXPORT Rect SubtractRects(const Rect& a, const Rect& b); +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. // @@ -106,7 +106,7 @@ UI_EXPORT Rect SubtractRects(const Rect& a, const Rect& b); // 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. -UI_EXPORT Rect BoundingRect(const Point& p1, const Point& p2); +GFX_EXPORT Rect BoundingRect(const Point& p1, const Point& p2); inline Rect ScaleToEnclosingRect(const Rect& rect, float x_scale, diff --git a/chromium/ui/gfx/rect_base.h b/chromium/ui/gfx/rect_base.h index f1a286323ec..412836ced19 100644 --- a/chromium/ui/gfx/rect_base.h +++ b/chromium/ui/gfx/rect_base.h @@ -24,7 +24,7 @@ template<typename Class, typename InsetsClass, typename VectorClass, typename Type> -class UI_EXPORT RectBase { +class GFX_EXPORT RectBase { public: Type x() const { return origin_.x(); } void set_x(Type x) { origin_.set_x(x); } @@ -143,6 +143,16 @@ class UI_EXPORT RectBase { // same height) with the given rectangle, and the rectangles do not overlap. bool SharesEdgeWith(const Class& rect) const; + // Returns the manhattan distance from the rect to the point. If the point is + // inside the rect, returns 0. + Type ManhattanDistanceToPoint(const PointClass& point) const; + + // Returns the manhattan distance between the contents of this rect and the + // contents of the given rect. That is, if the intersection of the two rects + // is non-empty then the function returns 0. If the rects share a side, it + // returns the smallest non-zero value appropriate for Type. + Type ManhattanInternalDistance(const Class& rect) const; + protected: RectBase(const PointClass& origin, const SizeClass& size) : origin_(origin), size_(size) {} diff --git a/chromium/ui/gfx/rect_base_impl.h b/chromium/ui/gfx/rect_base_impl.h index e44bc00bace..52201691a1b 100644 --- a/chromium/ui/gfx/rect_base_impl.h +++ b/chromium/ui/gfx/rect_base_impl.h @@ -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 <limits> + #include "ui/gfx/rect_base.h" #include "base/logging.h" @@ -9,7 +11,7 @@ // This file provides the implementation for RectBaese template and // used to instantiate the base class for Rect and RectF classes. -#if !defined(UI_IMPLEMENTATION) +#if !defined(GFX_IMPLEMENTATION) #error "This file is intended for UI implementation only" #endif @@ -314,4 +316,40 @@ bool RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>:: (y() == rect.bottom() || bottom() == rect.y())); } +template<typename Class, + typename PointClass, + typename SizeClass, + typename InsetsClass, + typename VectorClass, + typename Type> +Type RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>:: + ManhattanDistanceToPoint(const PointClass& point) const { + Type x_distance = std::max<Type>(0, std::max( + x() - point.x(), point.x() - right())); + Type y_distance = std::max<Type>(0, std::max( + y() - point.y(), point.y() - bottom())); + + return x_distance + y_distance; +} + +template<typename Class, + typename PointClass, + typename SizeClass, + typename InsetsClass, + typename VectorClass, + typename Type> +Type RectBase<Class, PointClass, SizeClass, InsetsClass, VectorClass, Type>:: + ManhattanInternalDistance(const Class& rect) const { + Class c(x(), y(), width(), height()); + c.Union(rect); + + static const Type kEpsilon = std::numeric_limits<Type>::is_integer + ? 1 + : std::numeric_limits<Type>::epsilon(); + + Type x = std::max<Type>(0, c.width() - width() - rect.width() + kEpsilon); + Type y = std::max<Type>(0, c.height() - height() - rect.height() + kEpsilon); + return x + y; +} + } // namespace gfx diff --git a/chromium/ui/gfx/rect_conversions.h b/chromium/ui/gfx/rect_conversions.h index 854fb6ea392..988f6c76418 100644 --- a/chromium/ui/gfx/rect_conversions.h +++ b/chromium/ui/gfx/rect_conversions.h @@ -11,25 +11,25 @@ namespace gfx { // Returns the smallest Rect that encloses the given RectF. -UI_EXPORT Rect ToEnclosingRect(const RectF& rect); +GFX_EXPORT Rect ToEnclosingRect(const RectF& rect); // Returns the largest Rect that is enclosed by the given RectF. -UI_EXPORT Rect ToEnclosedRect(const RectF& rect); +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. -UI_EXPORT Rect ToNearestRect(const RectF& rect); +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|. -UI_EXPORT bool IsNearestRectWithinDistance( +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. -UI_EXPORT Rect ToFlooredRectDeprecated(const RectF& rect); +GFX_EXPORT Rect ToFlooredRectDeprecated(const RectF& rect); } // namespace gfx diff --git a/chromium/ui/gfx/rect_f.h b/chromium/ui/gfx/rect_f.h index 62bedf2e359..09de529a627 100644 --- a/chromium/ui/gfx/rect_f.h +++ b/chromium/ui/gfx/rect_f.h @@ -17,7 +17,7 @@ namespace gfx { class InsetsF; // A floating version of gfx::Rect. -class UI_EXPORT RectF +class GFX_EXPORT RectF : public RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float> { public: RectF() @@ -83,9 +83,9 @@ inline RectF operator+(const Vector2dF& lhs, const RectF& rhs) { return rhs + lhs; } -UI_EXPORT RectF IntersectRects(const RectF& a, const RectF& b); -UI_EXPORT RectF UnionRects(const RectF& a, const RectF& b); -UI_EXPORT RectF SubtractRects(const RectF& a, const RectF& b); +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, @@ -102,7 +102,7 @@ inline RectF ScaleRect(const RectF& r, float scale) { // 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. -UI_EXPORT RectF BoundingRect(const PointF& p1, const PointF& p2); +GFX_EXPORT RectF BoundingRect(const PointF& p1, const PointF& p2); #if !defined(COMPILER_MSVC) extern template class RectBase<RectF, PointF, SizeF, InsetsF, Vector2dF, float>; diff --git a/chromium/ui/gfx/rect_unittest.cc b/chromium/ui/gfx/rect_unittest.cc index 0b5f01eef3f..31a156b7910 100644 --- a/chromium/ui/gfx/rect_unittest.cc +++ b/chromium/ui/gfx/rect_unittest.cc @@ -865,4 +865,72 @@ TEST(RectTest, Corners) { EXPECT_EQ(PointF(4.2f, 6.2f).ToString(), f.bottom_right().ToString()); } +TEST(RectTest, ManhattanDistanceToPoint) { + Rect i(1, 2, 3, 4); + EXPECT_EQ(0, i.ManhattanDistanceToPoint(Point(1, 2))); + EXPECT_EQ(0, i.ManhattanDistanceToPoint(Point(4, 6))); + EXPECT_EQ(0, i.ManhattanDistanceToPoint(Point(2, 4))); + EXPECT_EQ(3, i.ManhattanDistanceToPoint(Point(0, 0))); + EXPECT_EQ(2, i.ManhattanDistanceToPoint(Point(2, 0))); + EXPECT_EQ(3, i.ManhattanDistanceToPoint(Point(5, 0))); + EXPECT_EQ(1, i.ManhattanDistanceToPoint(Point(5, 4))); + EXPECT_EQ(3, i.ManhattanDistanceToPoint(Point(5, 8))); + EXPECT_EQ(2, i.ManhattanDistanceToPoint(Point(3, 8))); + EXPECT_EQ(2, i.ManhattanDistanceToPoint(Point(0, 7))); + EXPECT_EQ(1, i.ManhattanDistanceToPoint(Point(0, 3))); + + RectF f(1.1f, 2.1f, 3.1f, 4.1f); + EXPECT_FLOAT_EQ(0.f, f.ManhattanDistanceToPoint(PointF(1.1f, 2.1f))); + EXPECT_FLOAT_EQ(0.f, f.ManhattanDistanceToPoint(PointF(4.2f, 6.f))); + EXPECT_FLOAT_EQ(0.f, f.ManhattanDistanceToPoint(PointF(2.f, 4.f))); + EXPECT_FLOAT_EQ(3.2f, f.ManhattanDistanceToPoint(PointF(0.f, 0.f))); + EXPECT_FLOAT_EQ(2.1f, f.ManhattanDistanceToPoint(PointF(2.f, 0.f))); + EXPECT_FLOAT_EQ(2.9f, f.ManhattanDistanceToPoint(PointF(5.f, 0.f))); + EXPECT_FLOAT_EQ(.8f, f.ManhattanDistanceToPoint(PointF(5.f, 4.f))); + EXPECT_FLOAT_EQ(2.6f, f.ManhattanDistanceToPoint(PointF(5.f, 8.f))); + EXPECT_FLOAT_EQ(1.8f, f.ManhattanDistanceToPoint(PointF(3.f, 8.f))); + EXPECT_FLOAT_EQ(1.9f, f.ManhattanDistanceToPoint(PointF(0.f, 7.f))); + EXPECT_FLOAT_EQ(1.1f, f.ManhattanDistanceToPoint(PointF(0.f, 3.f))); +} + +TEST(RectTest, ManhattanInternalDistance) { + Rect i(0, 0, 400, 400); + EXPECT_EQ(0, i.ManhattanInternalDistance(gfx::Rect(-1, 0, 2, 1))); + EXPECT_EQ(1, i.ManhattanInternalDistance(gfx::Rect(400, 0, 1, 400))); + EXPECT_EQ(2, i.ManhattanInternalDistance(gfx::Rect(-100, -100, 100, 100))); + EXPECT_EQ(2, i.ManhattanInternalDistance(gfx::Rect(-101, 100, 100, 100))); + EXPECT_EQ(4, i.ManhattanInternalDistance(gfx::Rect(-101, -101, 100, 100))); + EXPECT_EQ(435, i.ManhattanInternalDistance(gfx::Rect(630, 603, 100, 100))); + + RectF f(0.0f, 0.0f, 400.0f, 400.0f); + static const float kEpsilon = std::numeric_limits<float>::epsilon(); + + EXPECT_FLOAT_EQ( + 0.0f, f.ManhattanInternalDistance(gfx::RectF(-1.0f, 0.0f, 2.0f, 1.0f))); + EXPECT_FLOAT_EQ( + kEpsilon, + f.ManhattanInternalDistance(gfx::RectF(400.0f, 0.0f, 1.0f, 400.0f))); + EXPECT_FLOAT_EQ(2.0f * kEpsilon, + f.ManhattanInternalDistance( + gfx::RectF(-100.0f, -100.0f, 100.0f, 100.0f))); + EXPECT_FLOAT_EQ( + 1.0f + kEpsilon, + f.ManhattanInternalDistance(gfx::RectF(-101.0f, 100.0f, 100.0f, 100.0f))); + EXPECT_FLOAT_EQ(2.0f + 2.0f * kEpsilon, + f.ManhattanInternalDistance( + gfx::RectF(-101.0f, -101.0f, 100.0f, 100.0f))); + EXPECT_FLOAT_EQ( + 433.0f + 2.0f * kEpsilon, + f.ManhattanInternalDistance(gfx::RectF(630.0f, 603.0f, 100.0f, 100.0f))); + + EXPECT_FLOAT_EQ( + 0.0f, f.ManhattanInternalDistance(gfx::RectF(-1.0f, 0.0f, 1.1f, 1.0f))); + EXPECT_FLOAT_EQ( + 0.1f + kEpsilon, + f.ManhattanInternalDistance(gfx::RectF(-1.5f, 0.0f, 1.4f, 1.0f))); + EXPECT_FLOAT_EQ( + kEpsilon, + f.ManhattanInternalDistance(gfx::RectF(-1.5f, 0.0f, 1.5f, 1.0f))); +} + } // namespace gfx diff --git a/chromium/ui/gfx/render_text.cc b/chromium/ui/gfx/render_text.cc index 47f42e37cb6..e8e3436f11c 100644 --- a/chromium/ui/gfx/render_text.cc +++ b/chromium/ui/gfx/render_text.cc @@ -5,6 +5,7 @@ #include "ui/gfx/render_text.h" #include <algorithm> +#include <climits> #include "base/i18n/break_iterator.h" #include "base/logging.h" @@ -27,7 +28,7 @@ namespace { // All chars are replaced by this char when the password style is set. // TODO(benrg): GTK uses the first of U+25CF, U+2022, U+2731, U+273A, '*' // that's available in the font (find_invisible_char() in gtkentry.c). -const char16 kPasswordReplacementChar = '*'; +const base::char16 kPasswordReplacementChar = '*'; // Default color used for the text and cursor. const SkColor kDefaultColor = SK_ColorBLACK; @@ -44,6 +45,33 @@ const SkScalar kLineThickness = (SK_Scalar1 / 18); // Fraction of the text size to use for a top margin of a diagonal strike. const SkScalar kDiagonalStrikeMarginOffset = (SK_Scalar1 / 4); +// Invalid value of baseline. Assigning this value to |baseline_| causes +// re-calculation of baseline. +const int kInvalidBaseline = INT_MAX; + +// Returns the baseline, with which the text best appears vertically centered. +int DetermineBaselineCenteringText(const Rect& display_rect, + const FontList& font_list) { + const int display_height = display_rect.height(); + const int font_height = font_list.GetHeight(); + // Lower and upper bound of baseline shift as we try to show as much area of + // text as possible. In particular case of |display_height| == |font_height|, + // we do not want to shift the baseline. + const int min_shift = std::min(0, display_height - font_height); + const int max_shift = std::abs(display_height - font_height); + const int baseline = font_list.GetBaseline(); + const int cap_height = font_list.GetCapHeight(); + const int internal_leading = baseline - cap_height; + // Some platforms don't support getting the cap height, and simply return + // the entire font ascent from GetCapHeight(). Centering the ascent makes + // the font look too low, so if GetCapHeight() returns the ascent, center + // the entire font height instead. + const int space = + display_height - ((internal_leading != 0) ? cap_height : font_height); + const int baseline_shift = space / 2 - internal_leading; + return baseline + std::max(min_shift, std::min(max_shift, baseline_shift)); +} + // Converts |gfx::Font::FontStyle| flags to |SkTypeface::Style| flags. SkTypeface::Style ConvertFontStyleToSkiaTypefaceStyle(int font_style) { int skia_style = SkTypeface::kNormal; @@ -348,16 +376,9 @@ void RenderText::SetHorizontalAlignment(HorizontalAlignment alignment) { } } -void RenderText::SetVerticalAlignment(VerticalAlignment alignment) { - if (vertical_alignment_ != alignment) { - vertical_alignment_ = alignment; - display_offset_ = Vector2d(); - cached_bounds_and_offset_valid_ = false; - } -} - void RenderText::SetFontList(const FontList& font_list) { font_list_ = font_list; + baseline_ = kInvalidBaseline; cached_bounds_and_offset_valid_ = false; ResetLayout(); } @@ -414,6 +435,7 @@ void RenderText::SetMultiline(bool multiline) { void RenderText::SetDisplayRect(const Rect& r) { display_rect_ = r; + baseline_ = kInvalidBaseline; cached_bounds_and_offset_valid_ = false; lines_.clear(); } @@ -609,6 +631,7 @@ void RenderText::SetDirectionalityMode(DirectionalityMode mode) { directionality_mode_ = mode; text_direction_ = base::i18n::UNKNOWN_DIRECTION; + cached_bounds_and_offset_valid_ = false; ResetLayout(); } @@ -644,10 +667,22 @@ VisualCursorDirection RenderText::GetVisualDirectionOfLogicalEnd() { CURSOR_RIGHT : CURSOR_LEFT; } +SizeF RenderText::GetStringSizeF() { + const Size size = GetStringSize(); + return SizeF(size.width(), size.height()); +} + int RenderText::GetContentWidth() { return GetStringSize().width() + (cursor_enabled_ ? 1 : 0); } +int RenderText::GetBaseline() { + if (baseline_ == kInvalidBaseline) + baseline_ = DetermineBaselineCenteringText(display_rect(), font_list()); + DCHECK_NE(kInvalidBaseline, baseline_); + return baseline_; +} + void RenderText::Draw(Canvas* canvas) { EnsureLayout(); @@ -779,7 +814,6 @@ void RenderText::SetTextShadows(const ShadowValues& shadows) { RenderText::RenderText() : horizontal_alignment_(base::i18n::IsRTL() ? ALIGN_RIGHT : ALIGN_LEFT), - vertical_alignment_(ALIGN_VCENTER), directionality_mode_(DIRECTIONALITY_FROM_TEXT), text_direction_(base::i18n::UNKNOWN_DIRECTION), cursor_enabled_(true), @@ -801,6 +835,7 @@ RenderText::RenderText() fade_tail_(false), background_is_transparent_(false), clip_to_display_rect_(true), + baseline_(kInvalidBaseline), cached_bounds_and_offset_valid_(false) { } @@ -844,7 +879,7 @@ const BreakList<size_t>& RenderText::GetLineBreaks() { if (line_breaks_.max() != 0) return line_breaks_; - const string16& layout_text = GetLayoutText(); + const base::string16& layout_text = GetLayoutText(); const size_t text_length = layout_text.length(); line_breaks_.SetValue(0); line_breaks_.SetMax(text_length); @@ -871,7 +906,7 @@ void RenderText::ApplyCompositionAndSelectionStyles() { styles_[UNDERLINE].ApplyValue(true, composition_range_); // Apply the selected text color to the [un-reversed] selection range. - if (!selection().is_empty()) { + if (!selection().is_empty() && focused()) { const Range range(selection().GetMin(), selection().GetMax()); colors_.ApplyValue(selection_color_, range); } @@ -964,11 +999,16 @@ Vector2d RenderText::GetAlignmentOffset(size_t line_number) { if (horizontal_alignment_ == ALIGN_CENTER) offset.set_x(offset.x() / 2); } - if (vertical_alignment_ != ALIGN_TOP) { - offset.set_y(display_rect().height() - GetStringSize().height()); - if (vertical_alignment_ == ALIGN_VCENTER) - offset.set_y(offset.y() / 2); + + // Vertically center the text. + if (multiline_) { + const int text_height = lines_.back().preceding_heights + + lines_.back().size.height(); + offset.set_y((display_rect_.height() - text_height) / 2); + } else { + offset.set_y(GetBaseline() - GetLayoutTextBaseline()); } + return offset; } diff --git a/chromium/ui/gfx/render_text.h b/chromium/ui/gfx/render_text.h index 598f4e1d181..8696d690560 100644 --- a/chromium/ui/gfx/render_text.h +++ b/chromium/ui/gfx/render_text.h @@ -25,6 +25,7 @@ #include "ui/gfx/rect.h" #include "ui/gfx/selection_model.h" #include "ui/gfx/shadow_value.h" +#include "ui/gfx/size_f.h" #include "ui/gfx/text_constants.h" #include "ui/gfx/vector2d.h" @@ -151,7 +152,7 @@ struct Line { // visual layout. Support is built in for a cursor, a selection, simple styling, // complex scripts, and bi-directional text. Implementations provide mechanisms // for rendering and translation between logical and visual data. -class UI_EXPORT RenderText { +class GFX_EXPORT RenderText { public: virtual ~RenderText(); @@ -166,11 +167,6 @@ class UI_EXPORT RenderText { } void SetHorizontalAlignment(HorizontalAlignment alignment); - VerticalAlignment vertical_alignment() const { - return vertical_alignment_; - } - void SetVerticalAlignment(VerticalAlignment alignment); - const FontList& font_list() const { return font_list_; } void SetFontList(const FontList& font_list); void SetFont(const Font& font); @@ -311,8 +307,11 @@ class UI_EXPORT RenderText { // RenderText. bool GetStyle(TextStyle style) const; - // Set the text directionality mode and get the text direction yielded. + // Set or get the text directionality mode and get the text direction yielded. void SetDirectionalityMode(DirectionalityMode mode); + DirectionalityMode directionality_mode() const { + return directionality_mode_; + } base::i18n::TextDirection GetTextDirection(); // Returns the visual movement direction corresponding to the logical end @@ -326,13 +325,22 @@ class UI_EXPORT RenderText { // shadows. virtual Size GetStringSize() = 0; + // This is same as GetStringSize except that fractional size is returned. + // The default implementation is same as GetStringSize. Certain platforms that + // compute the text size as floating-point values, like Mac, will override + // this method. + // See comment in Canvas::GetStringWidthF for its usage. + virtual SizeF GetStringSizeF(); + // Returns the width of the content (which is the wrapped width in multiline // mode). Reserves room for the cursor if |cursor_enabled_| is true. int GetContentWidth(); - // Returns the common baseline of the text. The returned value is the vertical - // offset from the top of |display_rect| to the text baseline, in pixels. - virtual int GetBaseline() = 0; + // Returns the common baseline of the text. The return value is the vertical + // offset from the top of |display_rect_| to the text baseline, in pixels. + // The baseline is determined from the font list and display rect, and does + // not depend on the text. + int GetBaseline(); void Draw(Canvas* canvas); @@ -346,12 +354,19 @@ class UI_EXPORT RenderText { // Gets the SelectionModel from a visual point in local coordinates. virtual SelectionModel FindCursorPosition(const Point& point) = 0; - // Get the visual bounds of a cursor at |selection|. These bounds typically - // represent a vertical line, but if |insert_mode| is true they contain the - // bounds of the associated glyph. These bounds 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. - Rect GetCursorBounds(const SelectionModel& selection, bool insert_mode); + // 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; + + // Get the visual bounds of a cursor at |caret|. These bounds typically + // represent a vertical line if |insert_mode| is true. Pass false for + // |insert_mode| to retrieve the bounds of the associated glyph. These bounds + // 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. + Rect GetCursorBounds(const SelectionModel& caret, bool insert_mode); // Compute the current cursor bounds, panning the text to show the cursor in // the display rect if necessary. These bounds are in local coordinates. @@ -390,6 +405,30 @@ class UI_EXPORT RenderText { const std::vector<internal::Line>& lines() const { return lines_; } void set_lines(std::vector<internal::Line>* lines) { lines_.swap(*lines); } + // Returns the baseline of the current text. The return value depends on + // the text and its layout while the return value of GetBaseline() doesn't. + // GetAlignmentOffset() takes into account the difference between them. + // + // We'd like a RenderText to show the text always on the same baseline + // regardless of the text, so the text does not jump up or down depending + // on the text. However, underlying layout engines return different baselines + // depending on the text. In general, layout engines determine the minimum + // bounding box for the text and return the baseline from the top of the + // bounding box. So the baseline changes depending on font metrics used to + // layout the text. + // + // For example, suppose there are FontA and FontB and the baseline of FontA + // is smaller than the one of FontB. If the text is laid out only with FontA, + // then the baseline of FontA may be returned. If the text includes some + // characters which are laid out with FontB, then the baseline of FontB may + // be returned. + // + // GetBaseline() returns the fixed baseline regardless of the text. + // GetLayoutTextBaseline() returns the baseline determined by the underlying + // layout engine, and it changes depending on the text. GetAlignmentOffset() + // returns the difference between them. + virtual int GetLayoutTextBaseline() = 0; + const Vector2d& GetUpdatedDisplayOffset(); void set_cached_bounds_and_offset_valid(bool valid) { @@ -441,10 +480,6 @@ class UI_EXPORT RenderText { virtual size_t TextIndexToLayoutIndex(size_t index) const = 0; virtual size_t LayoutIndexToTextIndex(size_t index) const = 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; - // Reset the layout to be invalid. virtual void ResetLayout() = 0; @@ -509,6 +544,7 @@ class UI_EXPORT RenderText { FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_MinWidth); FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_NormalWidth); FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_SufficientWidth); + FRIEND_TEST_ALL_PREFIXES(RenderTextTest, Multiline_Newline); // Set the cursor to |position|, with the caret trailing the previous // grapheme, or if there is no previous grapheme, leading the cursor position. @@ -534,10 +570,6 @@ class UI_EXPORT RenderText { // default is to align left if the application UI is LTR and right if RTL. HorizontalAlignment horizontal_alignment_; - // Vertical alignment of the text with respect to |display_rect_|. The - // default is to align vertically centered. - VerticalAlignment vertical_alignment_; - // The text directionality mode, defaults to DIRECTIONALITY_FROM_TEXT. DirectionalityMode directionality_mode_; @@ -623,6 +655,11 @@ class UI_EXPORT RenderText { // Get this point with GetUpdatedDisplayOffset (or risk using a stale value). Vector2d display_offset_; + // The baseline of the text. This is determined from the height of the + // display area and the cap height of the font list so the text is vertically + // centered. + int baseline_; + // The cached bounds and offset are invalidated by changes to the cursor, // selection, font, and other operations that adjust the visible text bounds. bool cached_bounds_and_offset_valid_; diff --git a/chromium/ui/gfx/render_text_mac.cc b/chromium/ui/gfx/render_text_mac.cc index 2fcea01b157..4feb9302c18 100644 --- a/chromium/ui/gfx/render_text_mac.cc +++ b/chromium/ui/gfx/render_text_mac.cc @@ -25,12 +25,12 @@ RenderTextMac::~RenderTextMac() { Size RenderTextMac::GetStringSize() { EnsureLayout(); - return string_size_; + return Size(std::ceil(string_size_.width()), string_size_.height()); } -int RenderTextMac::GetBaseline() { +SizeF RenderTextMac::GetStringSizeF() { EnsureLayout(); - return common_baseline_; + return string_size_; } SelectionModel RenderTextMac::FindCursorPosition(const Point& point) { @@ -54,6 +54,11 @@ std::vector<RenderText::FontSpan> RenderTextMac::GetFontSpansForTesting() { return spans; } +int RenderTextMac::GetLayoutTextBaseline() { + EnsureLayout(); + return common_baseline_; +} + SelectionModel RenderTextMac::AdjacentCharSelectionModel( const SelectionModel& selection, VisualCursorDirection direction) { @@ -107,10 +112,7 @@ void RenderTextMac::EnsureLayout() { runs_valid_ = false; const Font& font = GetPrimaryFont(); - base::ScopedCFTypeRef<CFStringRef> font_name_cf_string( - base::SysUTF8ToCFStringRef(font.GetFontName())); - base::ScopedCFTypeRef<CTFontRef> ct_font( - CTFontCreateWithName(font_name_cf_string, font.GetFontSize(), NULL)); + CTFontRef ct_font = base::mac::NSToCFCast(font.GetNativeFont()); const void* keys[] = { kCTFontAttributeName }; const void* values[] = { ct_font }; @@ -149,7 +151,7 @@ void RenderTextMac::EnsureLayout() { CGFloat font_list_baseline = font_list().GetBaseline(); ascent = std::max(ascent, font_list_baseline); descent = std::max(descent, font_list_height - font_list_baseline); - string_size_ = Size(std::ceil(width), ascent + descent + leading); + string_size_ = SizeF(width, ascent + descent + leading); common_baseline_ = ascent; } diff --git a/chromium/ui/gfx/render_text_mac.h b/chromium/ui/gfx/render_text_mac.h index be5f12865c0..3a18a0fad45 100644 --- a/chromium/ui/gfx/render_text_mac.h +++ b/chromium/ui/gfx/render_text_mac.h @@ -27,12 +27,13 @@ class RenderTextMac : public RenderText { // Overridden from RenderText: virtual Size GetStringSize() OVERRIDE; - virtual int GetBaseline() OVERRIDE; + virtual SizeF GetStringSizeF() 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; @@ -81,7 +82,7 @@ class RenderTextMac : public RenderText { base::ScopedCFTypeRef<CFMutableArrayRef> attributes_; // Visual dimensions of the text. Computed by |EnsureLayout()|. - Size string_size_; + SizeF string_size_; // Common baseline for this line of text. Computed by |EnsureLayout()|. SkScalar common_baseline_; diff --git a/chromium/ui/gfx/render_text_ozone.cc b/chromium/ui/gfx/render_text_ozone.cc new file mode 100644 index 00000000000..058b5a6389d --- /dev/null +++ b/chromium/ui/gfx/render_text_ozone.cc @@ -0,0 +1,13 @@ +// 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/render_text.h" + +namespace gfx { + +RenderText* RenderText::CreateInstance() { + return NULL; +} + +} // namespace gfx diff --git a/chromium/ui/gfx/render_text_linux.cc b/chromium/ui/gfx/render_text_pango.cc index 4b7b93474ae..f120a5c10bb 100644 --- a/chromium/ui/gfx/render_text_linux.cc +++ b/chromium/ui/gfx/render_text_pango.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/render_text_linux.h" +#include "ui/gfx/render_text_pango.h" #include <pango/pangocairo.h> #include <algorithm> @@ -67,7 +67,7 @@ void SetPangoUnderlineMetrics(PangoFontDescription *desc, // Since caret_pos is used internally, we could save utf8 index for caret_pos // to avoid conversion. -RenderTextLinux::RenderTextLinux() +RenderTextPango::RenderTextPango() : layout_(NULL), current_line_(NULL), log_attrs_(NULL), @@ -75,11 +75,11 @@ RenderTextLinux::RenderTextLinux() layout_text_(NULL) { } -RenderTextLinux::~RenderTextLinux() { +RenderTextPango::~RenderTextPango() { ResetLayout(); } -Size RenderTextLinux::GetStringSize() { +Size RenderTextPango::GetStringSize() { EnsureLayout(); int width = 0, height = 0; pango_layout_get_pixel_size(layout_, &width, &height); @@ -91,16 +91,7 @@ Size RenderTextLinux::GetStringSize() { return Size(width, std::max(height, font_list().GetHeight())); } -int RenderTextLinux::GetBaseline() { - EnsureLayout(); - // Keep a consistent baseline between this particular string's PangoLayout and - // potentially larger text supported by the FontList. - // See the example in GetStringSize(). - return std::max(PANGO_PIXELS(pango_layout_get_baseline(layout_)), - font_list().GetBaseline()); -} - -SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) { +SelectionModel RenderTextPango::FindCursorPosition(const Point& point) { EnsureLayout(); if (text().empty()) @@ -129,7 +120,7 @@ SelectionModel RenderTextLinux::FindCursorPosition(const Point& point) { (trailing > 0) ? CURSOR_BACKWARD : CURSOR_FORWARD); } -std::vector<RenderText::FontSpan> RenderTextLinux::GetFontSpansForTesting() { +std::vector<RenderText::FontSpan> RenderTextPango::GetFontSpansForTesting() { EnsureLayout(); std::vector<RenderText::FontSpan> spans; @@ -146,7 +137,12 @@ std::vector<RenderText::FontSpan> RenderTextLinux::GetFontSpansForTesting() { return spans; } -SelectionModel RenderTextLinux::AdjacentCharSelectionModel( +int RenderTextPango::GetLayoutTextBaseline() { + EnsureLayout(); + return PANGO_PIXELS(pango_layout_get_baseline(layout_)); +} + +SelectionModel RenderTextPango::AdjacentCharSelectionModel( const SelectionModel& selection, VisualCursorDirection direction) { GSList* run = GetRunContainingCaret(selection); @@ -186,7 +182,7 @@ SelectionModel RenderTextLinux::AdjacentCharSelectionModel( FirstSelectionModelInsideRun(item) : LastSelectionModelInsideRun(item); } -SelectionModel RenderTextLinux::AdjacentWordSelectionModel( +SelectionModel RenderTextPango::AdjacentWordSelectionModel( const SelectionModel& selection, VisualCursorDirection direction) { if (obscured()) @@ -214,14 +210,14 @@ SelectionModel RenderTextLinux::AdjacentWordSelectionModel( return cur; } -Range RenderTextLinux::GetGlyphBounds(size_t index) { +Range RenderTextPango::GetGlyphBounds(size_t index) { PangoRectangle pos; pango_layout_index_to_pos(layout_, TextIndexToLayoutIndex(index), &pos); // TODO(derat): Support fractional ranges for subpixel positioning? return Range(PANGO_PIXELS(pos.x), PANGO_PIXELS(pos.x + pos.width)); } -std::vector<Rect> RenderTextLinux::GetSubstringBounds(const Range& range) { +std::vector<Rect> RenderTextPango::GetSubstringBounds(const Range& range) { DCHECK_LE(range.GetMax(), text().length()); if (range.is_empty()) return std::vector<Rect>(); @@ -250,7 +246,7 @@ std::vector<Rect> RenderTextLinux::GetSubstringBounds(const Range& range) { return bounds; } -size_t RenderTextLinux::TextIndexToLayoutIndex(size_t index) const { +size_t RenderTextPango::TextIndexToLayoutIndex(size_t index) const { DCHECK(layout_); ptrdiff_t offset = gfx::UTF16IndexToOffset(text(), 0, index); // Clamp layout indices to the length of the text actually used for layout. @@ -259,14 +255,14 @@ size_t RenderTextLinux::TextIndexToLayoutIndex(size_t index) const { return (layout_pointer - layout_text_); } -size_t RenderTextLinux::LayoutIndexToTextIndex(size_t index) const { +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); } -bool RenderTextLinux::IsCursorablePosition(size_t position) { +bool RenderTextPango::IsCursorablePosition(size_t position) { if (position == 0 && text().empty()) return true; if (position >= text().length()) @@ -283,7 +279,7 @@ bool RenderTextLinux::IsCursorablePosition(size_t position) { offset < g_utf8_strlen(layout_text_, -1)); } -void RenderTextLinux::ResetLayout() { +void RenderTextPango::ResetLayout() { // set_cached_bounds_and_offset_valid(false) is done in RenderText for every // operation that triggers ResetLayout(). if (layout_) { @@ -303,7 +299,7 @@ void RenderTextLinux::ResetLayout() { layout_text_ = NULL; } -void RenderTextLinux::EnsureLayout() { +void RenderTextPango::EnsureLayout() { if (layout_ == NULL) { cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0); @@ -342,7 +338,7 @@ void RenderTextLinux::EnsureLayout() { } } -void RenderTextLinux::SetupPangoAttributes(PangoLayout* layout) { +void RenderTextPango::SetupPangoAttributes(PangoLayout* layout) { PangoAttrList* attrs = pango_attr_list_new(); // Splitting text runs to accommodate styling can break Arabic glyph shaping. @@ -377,11 +373,11 @@ void RenderTextLinux::SetupPangoAttributes(PangoLayout* layout) { pango_attr_list_unref(attrs); } -void RenderTextLinux::DrawVisualText(Canvas* canvas) { +void RenderTextPango::DrawVisualText(Canvas* canvas) { DCHECK(layout_); // Skia will draw glyphs with respect to the baseline. - Vector2d offset(GetLineOffset(0) + Vector2d(0, GetBaseline())); + Vector2d offset(GetLineOffset(0) + Vector2d(0, GetLayoutTextBaseline())); SkScalar x = SkIntToScalar(offset.x()); SkScalar y = SkIntToScalar(offset.y()); @@ -476,7 +472,7 @@ void RenderTextLinux::DrawVisualText(Canvas* canvas) { UndoCompositionAndSelectionStyles(); } -GSList* RenderTextLinux::GetRunContainingCaret( +GSList* RenderTextPango::GetRunContainingCaret( const SelectionModel& caret) const { size_t position = TextIndexToLayoutIndex(caret.caret_pos()); LogicalCursorDirection affinity = caret.caret_affinity(); @@ -491,28 +487,28 @@ GSList* RenderTextLinux::GetRunContainingCaret( return NULL; } -SelectionModel RenderTextLinux::FirstSelectionModelInsideRun( +SelectionModel RenderTextPango::FirstSelectionModelInsideRun( const PangoItem* item) { size_t caret = IndexOfAdjacentGrapheme( LayoutIndexToTextIndex(item->offset), CURSOR_FORWARD); return SelectionModel(caret, CURSOR_BACKWARD); } -SelectionModel RenderTextLinux::LastSelectionModelInsideRun( +SelectionModel RenderTextPango::LastSelectionModelInsideRun( const PangoItem* item) { size_t caret = IndexOfAdjacentGrapheme( LayoutIndexToTextIndex(item->offset + item->length), CURSOR_BACKWARD); return SelectionModel(caret, CURSOR_FORWARD); } -size_t RenderTextLinux::GetGlyphTextIndex(PangoLayoutRun* run, +size_t RenderTextPango::GetGlyphTextIndex(PangoLayoutRun* run, int glyph_index) const { return LayoutIndexToTextIndex(run->item->offset + run->glyphs->log_clusters[glyph_index]); } RenderText* RenderText::CreateInstance() { - return new RenderTextLinux; + return new RenderTextPango; } } // namespace gfx diff --git a/chromium/ui/gfx/render_text_linux.h b/chromium/ui/gfx/render_text_pango.h index 1500fc0adef..ba7361c4d30 100644 --- a/chromium/ui/gfx/render_text_linux.h +++ b/chromium/ui/gfx/render_text_pango.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_RENDER_TEXT_LINUX_H_ -#define UI_GFX_RENDER_TEXT_LINUX_H_ +#ifndef UI_GFX_RENDER_TEXT_PANGO_H_ +#define UI_GFX_RENDER_TEXT_PANGO_H_ #include <pango/pango.h> #include <vector> @@ -12,20 +12,20 @@ namespace gfx { -// RenderTextLinux is the Linux implementation of RenderText using Pango. -class RenderTextLinux : public RenderText { +// RenderTextPango is the Linux implementation of RenderText using Pango. +class RenderTextPango : public RenderText { public: - RenderTextLinux(); - virtual ~RenderTextLinux(); + RenderTextPango(); + virtual ~RenderTextPango(); // Overridden from RenderText: virtual Size GetStringSize() OVERRIDE; - virtual int GetBaseline() 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; @@ -80,9 +80,9 @@ class RenderTextLinux : public RenderText { // The text in the |layout_|. const char* layout_text_; - DISALLOW_COPY_AND_ASSIGN(RenderTextLinux); + DISALLOW_COPY_AND_ASSIGN(RenderTextPango); }; } // namespace gfx -#endif // UI_GFX_RENDER_TEXT_LINUX_H_ +#endif // UI_GFX_RENDER_TEXT_PANGO_H_ diff --git a/chromium/ui/gfx/render_text_unittest.cc b/chromium/ui/gfx/render_text_unittest.cc index 52cb8344b37..c8c50d42814 100644 --- a/chromium/ui/gfx/render_text_unittest.cc +++ b/chromium/ui/gfx/render_text_unittest.cc @@ -8,6 +8,7 @@ #include "base/format_macros.h" #include "base/memory/scoped_ptr.h" +#include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" @@ -19,8 +20,8 @@ #include "ui/gfx/render_text_win.h" #endif -#if defined(OS_LINUX) -#include "ui/gfx/render_text_linux.h" +#if defined(OS_LINUX) && !defined(USE_OZONE) +#include "ui/gfx/render_text_pango.h" #endif #if defined(TOOLKIT_GTK) @@ -34,11 +35,13 @@ namespace { // Various weak, LTR, RTL, and Bidi string cases with three characters each. const wchar_t kWeak[] = L" . "; const wchar_t kLtr[] = L"abc"; +const wchar_t kRtl[] = L"\x5d0\x5d1\x5d2"; +#if !defined(OS_MACOSX) const wchar_t kLtrRtl[] = L"a" L"\x5d0\x5d1"; const wchar_t kLtrRtlLtr[] = L"a" L"\x5d1" L"b"; -const wchar_t kRtl[] = L"\x5d0\x5d1\x5d2"; const wchar_t kRtlLtr[] = L"\x5d0\x5d1" L"a"; 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 @@ -63,6 +66,7 @@ void SetRTL(bool rtl) { EXPECT_EQ(rtl, base::i18n::IsRTL()); } +#if !defined(OS_MACOSX) // Ensure cursor movement in the specified |direction| yields |expected| values. void RunMoveCursorLeftRightTest(RenderText* render_text, const std::vector<SelectionModel>& expected, @@ -79,6 +83,7 @@ void RunMoveCursorLeftRightTest(RenderText* render_text, render_text->MoveCursor(LINE_BREAK, direction, false); EXPECT_EQ(expected.back(), render_text->selection_model()); } +#endif // !defined(OS_MACOSX) } // namespace @@ -182,7 +187,7 @@ TEST_F(RenderTextTest, ApplyColorAndStyle) { EXPECT_TRUE(render_text->styles()[ITALIC].EqualsForTesting(expected_italic)); } -#if defined(OS_LINUX) +#if defined(OS_LINUX) && !defined(USE_OZONE) TEST_F(RenderTextTest, PangoAttributes) { scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); render_text->SetText(ASCIIToUTF16("012345678")); @@ -205,7 +210,7 @@ TEST_F(RenderTextTest, PangoAttributes) { }; int start = 0, end = 0; - RenderTextLinux* rt_linux = static_cast<RenderTextLinux*>(render_text.get()); + RenderTextPango* rt_linux = static_cast<RenderTextPango*>(render_text.get()); rt_linux->EnsureLayout(); PangoAttrList* attributes = pango_layout_get_attributes(rt_linux->layout_); PangoAttrIterator* iter = pango_attr_list_get_iterator(attributes); @@ -1137,6 +1142,7 @@ TEST_F(RenderTextTest, StringSizeEmptyString) { const FontList font_list("Arial,Symbol, 16px"); scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); render_text->SetFontList(font_list); + render_text->SetDisplayRect(Rect(0, 0, 0, font_list.GetHeight())); // The empty string respects FontList metrics for non-zero height // and baseline. @@ -1154,7 +1160,11 @@ TEST_F(RenderTextTest, StringSizeEmptyString) { TEST_F(RenderTextTest, StringSizeRespectsFontListMetrics) { // Check that Arial and Symbol have different font metrics. Font arial_font("Arial", 16); + ASSERT_EQ("arial", + StringToLowerASCII(arial_font.GetActualFontNameForTesting())); Font symbol_font("Symbol", 16); + ASSERT_EQ("symbol", + StringToLowerASCII(symbol_font.GetActualFontNameForTesting())); EXPECT_NE(arial_font.GetHeight(), symbol_font.GetHeight()); EXPECT_NE(arial_font.GetBaseline(), symbol_font.GetBaseline()); // "a" should be rendered with Arial, not with Symbol. @@ -1178,7 +1188,9 @@ TEST_F(RenderTextTest, StringSizeRespectsFontListMetrics) { // Check |smaller_font_text| is rendered with the smaller font. scoped_ptr<RenderText> render_text(RenderText::CreateInstance()); render_text->SetText(UTF8ToUTF16(smaller_font_text)); - render_text->SetFont(smaller_font); + render_text->SetFontList(FontList(smaller_font)); + render_text->SetDisplayRect(Rect(0, 0, 0, + render_text->font_list().GetHeight())); EXPECT_EQ(smaller_font.GetHeight(), render_text->GetStringSize().height()); EXPECT_EQ(smaller_font.GetBaseline(), render_text->GetBaseline()); @@ -1190,6 +1202,8 @@ TEST_F(RenderTextTest, StringSizeRespectsFontListMetrics) { fonts.push_back(larger_font); const FontList font_list(fonts); render_text->SetFontList(font_list); + render_text->SetDisplayRect(Rect(0, 0, 0, + render_text->font_list().GetHeight())); EXPECT_LT(smaller_font.GetHeight(), render_text->GetStringSize().height()); EXPECT_LT(smaller_font.GetBaseline(), render_text->GetBaseline()); EXPECT_EQ(font_list.GetHeight(), render_text->GetStringSize().height()); @@ -1291,21 +1305,19 @@ TEST_F(RenderTextTest, GetTextOffset) { // Set display area's size equal to the font size. const Size font_size(render_text->GetContentWidth(), - render_text->GetStringSize().height()); + render_text->font_list().GetHeight()); Rect display_rect(font_size); render_text->SetDisplayRect(display_rect); Vector2d offset = render_text->GetLineOffset(0); EXPECT_TRUE(offset.IsZero()); - // Set display area's size greater than font size. - const int kEnlargement = 2; - display_rect.Inset(0, 0, -kEnlargement, -kEnlargement); + const int kEnlargementX = 2; + display_rect.Inset(0, 0, -kEnlargementX, 0); render_text->SetDisplayRect(display_rect); - // Check the default horizontal and vertical alignment. + // Check the default horizontal alignment. offset = render_text->GetLineOffset(0); - EXPECT_EQ(kEnlargement / 2, offset.y()); EXPECT_EQ(0, offset.x()); // Check explicitly setting the horizontal alignment. @@ -1314,21 +1326,20 @@ TEST_F(RenderTextTest, GetTextOffset) { EXPECT_EQ(0, offset.x()); render_text->SetHorizontalAlignment(ALIGN_CENTER); offset = render_text->GetLineOffset(0); - EXPECT_EQ(kEnlargement / 2, offset.x()); + EXPECT_EQ(kEnlargementX / 2, offset.x()); render_text->SetHorizontalAlignment(ALIGN_RIGHT); offset = render_text->GetLineOffset(0); - EXPECT_EQ(kEnlargement, offset.x()); + EXPECT_EQ(kEnlargementX, offset.x()); - // Check explicitly setting the vertical alignment. - render_text->SetVerticalAlignment(ALIGN_TOP); - offset = render_text->GetLineOffset(0); - EXPECT_EQ(0, offset.y()); - render_text->SetVerticalAlignment(ALIGN_VCENTER); - offset = render_text->GetLineOffset(0); - EXPECT_EQ(kEnlargement / 2, offset.y()); - render_text->SetVerticalAlignment(ALIGN_BOTTOM); + // Check that text is vertically centered within taller display rects. + const int kEnlargementY = display_rect.height(); + display_rect.Inset(0, 0, 0, -kEnlargementY); + render_text->SetDisplayRect(display_rect); + const Vector2d prev_offset = render_text->GetLineOffset(0); + display_rect.Inset(0, 0, 0, -2 * kEnlargementY); + render_text->SetDisplayRect(display_rect); offset = render_text->GetLineOffset(0); - EXPECT_EQ(kEnlargement, offset.y()); + EXPECT_EQ(prev_offset.y() + kEnlargementY, offset.y()); SetRTL(was_rtl); } @@ -1674,19 +1685,13 @@ TEST_F(RenderTextTest, Multiline_MinWidth) { // Ensure strings wrap onto multiple lines for a normal available width. TEST_F(RenderTextTest, Multiline_NormalWidth) { - // TODO(ckocagil): Enable this test on XP. -#if defined(OS_WIN) - if (base::win::GetVersion() < base::win::VERSION_VISTA) - return; -#endif - const struct { const wchar_t* const text; const Range first_line_char_range; const Range second_line_char_range; } kTestStrings[] = { { L"abc defg hijkl", Range(0, 9), Range(9, 14) }, - { L"qwertyuiop", Range(0, 8), Range(8, 10) }, + { L"qwertyzxcvbn", Range(0, 8), Range(8, 12) }, { L"\x062A\x0641\x0627\x062D\x05EA\x05E4\x05D5\x05D6\x05D9\x05DD", Range(4, 10), Range(0, 4) } }; @@ -1730,13 +1735,59 @@ TEST_F(RenderTextTest, Multiline_SufficientWidth) { EXPECT_EQ(1U, render_text->lines_.size()); } } -#endif // defined(OS_WIN) -#if defined(OS_WIN) +TEST_F(RenderTextTest, Multiline_Newline) { + const struct { + const wchar_t* const text; + // Ranges of the characters on each line preceding the newline. + const Range first_line_char_range; + const Range second_line_char_range; + } kTestStrings[] = { + { L"abc\ndef", Range(0, 3), Range(4, 7) }, + { L"a \n b ", Range(0, 2), Range(3, 6) }, + { L"\n" , Range::InvalidRange(), Range::InvalidRange() } + }; + + scoped_ptr<RenderTextWin> render_text( + static_cast<RenderTextWin*>(RenderText::CreateInstance())); + render_text->SetDisplayRect(Rect(200, 1000)); + render_text->SetMultiline(true); + Canvas canvas; + + for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestStrings); ++i) { + SCOPED_TRACE(base::StringPrintf("kTestStrings[%" PRIuS "]", i)); + render_text->SetText(WideToUTF16(kTestStrings[i].text)); + render_text->Draw(&canvas); + + ASSERT_EQ(2U, render_text->lines_.size()); + + const Range first_expected_range = kTestStrings[i].first_line_char_range; + ASSERT_EQ(first_expected_range.IsValid() ? 2U : 1U, + render_text->lines_[0].segments.size()); + if (first_expected_range.IsValid()) + EXPECT_EQ(first_expected_range, + render_text->lines_[0].segments[0].char_range); + + const internal::LineSegment& newline_segment = + render_text->lines_[0].segments[first_expected_range.IsValid() ? 1 : 0]; + ASSERT_EQ(1U, newline_segment.char_range.length()); + EXPECT_EQ(L'\n', kTestStrings[i].text[newline_segment.char_range.start()]); + + const Range second_expected_range = kTestStrings[i].second_line_char_range; + ASSERT_EQ(second_expected_range.IsValid() ? 1U : 0U, + render_text->lines_[1].segments.size()); + if (second_expected_range.IsValid()) + EXPECT_EQ(second_expected_range, + render_text->lines_[1].segments[0].char_range); + } +} + + TEST_F(RenderTextTest, Win_BreakRunsByUnicodeBlocks) { scoped_ptr<RenderTextWin> render_text( static_cast<RenderTextWin*>(RenderText::CreateInstance())); + // 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()); @@ -1750,8 +1801,7 @@ TEST_F(RenderTextTest, Win_BreakRunsByUnicodeBlocks) { 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); - } -#endif // !defined(OS_WIN) +#endif // defined(OS_WIN) } // namespace gfx diff --git a/chromium/ui/gfx/render_text_win.cc b/chromium/ui/gfx/render_text_win.cc index e283de319ef..4afbc7fa71e 100644 --- a/chromium/ui/gfx/render_text_win.cc +++ b/chromium/ui/gfx/render_text_win.cc @@ -159,13 +159,15 @@ Range CharRangeToGlyphRange(const internal::TextRun& run, // Starting from |start_char|, finds a suitable line break position at or before // |available_width| using word break info from |breaks|. If |empty_line| is // true, this function will not roll back to |start_char| and |*next_char| will -// be greater than |start_char| (to avoid constructing empty lines). +// be greater than |start_char| (to avoid constructing empty lines). Returns +// whether to skip the line before |*next_char|. // TODO(ckocagil): Do not break ligatures and diacritics. // TextRun::logical_clusters might help. // TODO(ckocagil): We might have to reshape after breaking at ligatures. // See whether resolving the TODO above resolves this too. // TODO(ckocagil): Do not reserve width for whitespace at the end of lines. -void BreakRunAtWidth(const internal::TextRun& run, +bool BreakRunAtWidth(const wchar_t* text, + const internal::TextRun& run, const BreakList<size_t>& breaks, size_t start_char, int available_width, @@ -180,6 +182,11 @@ void BreakRunAtWidth(const internal::TextRun& run, *width = 0; for (size_t i = start_char; i < run.range.end(); ++i) { + if (U16_IS_SINGLE(text[i]) && text[i] == L'\n') { + *next_char = i + 1; + return true; + } + // |word| holds the word boundary at or before |i|, and |next_word| holds // the word boundary right after |i|. Advance both |word| and |next_word| // when |i| reaches |next_word|. @@ -198,20 +205,24 @@ void BreakRunAtWidth(const internal::TextRun& run, if (*width > available_width) { if (!empty_line || word_width < *width) { + // Roll back one word. *width -= word_width; *next_char = std::max(word->first, start_char); } else if (char_width < *width) { + // Roll back one character. *width -= char_width; *next_char = i; } else { + // Continue from the next character. *next_char = i + 1; } - return; + return true; } } *next_char = run.range.end(); + return false; } // For segments in the same run, checks the continuity and order of |x_range| @@ -246,6 +257,12 @@ void CheckLineIntegrity(const std::vector<internal::Line>& lines, } } +// Returns true if characters of |block_code| may trigger font fallback. +bool IsUnusualBlockCode(const UBlockCode block_code) { + return block_code == UBLOCK_GEOMETRIC_SHAPES || + block_code == UBLOCK_MISCELLANEOUS_SYMBOLS; +} + } // namespace namespace internal { @@ -302,12 +319,14 @@ class LineBreaker { int min_baseline, int min_height, bool multiline, + const wchar_t* text, const BreakList<size_t>* words, const ScopedVector<TextRun>& runs) : max_width_(max_width), min_baseline_(min_baseline), min_height_(min_height), multiline_(multiline), + text_(text), words_(words), runs_(runs), text_x_(0), @@ -320,7 +339,16 @@ class LineBreaker { // Breaks the run at given |run_index| into Line structs. void AddRun(int run_index) { const TextRun* run = runs_[run_index]; - if (multiline_ && line_x_ + run->width > max_width_) + bool run_fits = !multiline_; + if (multiline_ && line_x_ + run->width <= max_width_) { + DCHECK(!run->range.is_empty()); + const wchar_t first_char = text_[run->range.start()]; + // Uniscribe always puts newline characters in their own runs. + if (!U16_IS_SINGLE(first_char) || first_char != L'\n') + run_fits = true; + } + + if (!run_fits) BreakRun(run_index); else AddSegment(run_index, run->range, run->width); @@ -356,10 +384,10 @@ class LineBreaker { // Break the run until it fits the current line. while (next_char < run->range.end()) { const size_t current_char = next_char; - BreakRunAtWidth(*run, *words_, current_char, max_width_ - line_x_, - line_x_ == 0, &width, &next_char); + const bool skip_line = BreakRunAtWidth(text_, *run, *words_, current_char, + max_width_ - line_x_, line_x_ == 0, &width, &next_char); AddSegment(run_index, Range(current_char, next_char), width); - if (next_char < run->range.end()) + if (skip_line) AdvanceLine(); } } @@ -443,6 +471,7 @@ class LineBreaker { const int min_baseline_; const int min_height_; const bool multiline_; + const wchar_t* text_; const BreakList<size_t>* const words_; const ScopedVector<TextRun>& runs_; @@ -493,11 +522,6 @@ Size RenderTextWin::GetStringSize() { return multiline_string_size_; } -int RenderTextWin::GetBaseline() { - EnsureLayout(); - return lines()[0].baseline; -} - SelectionModel RenderTextWin::FindCursorPosition(const Point& point) { if (text().empty()) return SelectionModel(); @@ -541,6 +565,11 @@ std::vector<RenderText::FontSpan> RenderTextWin::GetFontSpansForTesting() { return spans; } +int RenderTextWin::GetLayoutTextBaseline() { + EnsureLayout(); + return lines()[0].baseline; +} + SelectionModel RenderTextWin::AdjacentCharSelectionModel( const SelectionModel& selection, VisualCursorDirection direction) { @@ -741,6 +770,7 @@ void RenderTextWin::EnsureLayout() { internal::LineBreaker line_breaker(display_rect().width() - 1, font_list().GetBaseline(), font_list().GetHeight(), multiline(), + GetLayoutText().c_str(), multiline() ? &GetLineBreaks() : NULL, runs_); for (size_t i = 0; i < runs_.size(); ++i) @@ -914,27 +944,31 @@ void RenderTextWin::ItemizeLogicalText() { // Clamp run lengths to avoid exceeding the maximum supported glyph count. if ((run_break - run->range.start()) > max_run_length) { run_break = run->range.start() + max_run_length; - if (!gfx::IsValidCodePointIndex(layout_text, run_break)) + if (!IsValidCodePointIndex(layout_text, run_break)) --run_break; } - // Break runs between characters in different code blocks. This avoids using - // fallback fonts for more characters than needed. http://crbug.com/278913 + // 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()) { 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) { - if (ublock_getCode(iter.get()) != first_block_code) { + 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; } } } - DCHECK(gfx::IsValidCodePointIndex(layout_text, run_break)); + DCHECK(IsValidCodePointIndex(layout_text, run_break)); style.UpdatePosition(LayoutIndexToTextIndex(run_break)); if (script_item_break == run_break) diff --git a/chromium/ui/gfx/render_text_win.h b/chromium/ui/gfx/render_text_win.h index 423e31fcad5..1a1ba4805cb 100644 --- a/chromium/ui/gfx/render_text_win.h +++ b/chromium/ui/gfx/render_text_win.h @@ -64,12 +64,12 @@ class RenderTextWin : public RenderText { // Overridden from RenderText: virtual Size GetStringSize() OVERRIDE; - virtual int GetBaseline() 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; diff --git a/chromium/ui/gfx/scoped_canvas.h b/chromium/ui/gfx/scoped_canvas.h new file mode 100644 index 00000000000..2e59a078760 --- /dev/null +++ b/chromium/ui/gfx/scoped_canvas.h @@ -0,0 +1,38 @@ +// 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_SCOPED_CANVAS_H_ +#define UI_GFX_SCOPED_CANVAS_H_ + +#include "ui/gfx/canvas.h" + +namespace gfx { + +// Saves the drawing state, and restores the state when going out of scope. +class ScopedCanvas { + public: + explicit ScopedCanvas(gfx::Canvas* canvas) : canvas_(canvas) { + if (canvas_) + canvas_->Save(); + } + ~ScopedCanvas() { + if (canvas_) + canvas_->Restore(); + } + void SetCanvas(gfx::Canvas* canvas) { + if (canvas_) + canvas_->Restore(); + canvas_ = canvas; + canvas_->Save(); + } + + private: + gfx::Canvas* canvas_; + + DISALLOW_COPY_AND_ASSIGN(ScopedCanvas); +}; + +} // namespace gfx + +#endif // UI_GFX_SCOPED_CANVAS_H_ diff --git a/chromium/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h b/chromium/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h index 9b0b77829b6..d305576701a 100644 --- a/chromium/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h +++ b/chromium/ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h @@ -17,7 +17,7 @@ class NSGraphicsContext; namespace gfx { // A class to save/restore the state of the current context. -class UI_EXPORT ScopedNSGraphicsContextSaveGState { +class GFX_EXPORT ScopedNSGraphicsContextSaveGState { public: ScopedNSGraphicsContextSaveGState(); ~ScopedNSGraphicsContextSaveGState(); diff --git a/chromium/ui/gfx/screen.h b/chromium/ui/gfx/screen.h index a181cc8d256..1d36d1b51cb 100644 --- a/chromium/ui/gfx/screen.h +++ b/chromium/ui/gfx/screen.h @@ -25,7 +25,7 @@ class Rect; // computer -- see the Display class for that. A single Screen object exists on // most operating systems regardless of the number of connected displays. On // Windows 8, two Screens exist: one for Metro UI and another for the desktop. -class UI_EXPORT Screen { +class GFX_EXPORT Screen { public: // Retrieves the Screen that the specified NativeView belongs to. A value of // NULL is treated as |SCREEN_TYPE_NATIVE|. diff --git a/chromium/ui/gfx/screen_mac.mm b/chromium/ui/gfx/screen_mac.mm index 28707ca7ea3..51c0b665b7e 100644 --- a/chromium/ui/gfx/screen_mac.mm +++ b/chromium/ui/gfx/screen_mac.mm @@ -7,6 +7,8 @@ #import <ApplicationServices/ApplicationServices.h> #import <Cocoa/Cocoa.h> +#include <map> + #include "base/logging.h" #include "base/mac/sdk_forward_declarations.h" #include "ui/gfx/display.h" @@ -42,15 +44,16 @@ NSScreen* GetMatchingScreen(const gfx::Rect& match_rect) { return max_screen; } -gfx::Display GetDisplayForScreen(NSScreen* screen, bool is_primary) { +gfx::Display GetDisplayForScreen(NSScreen* screen) { NSRect frame = [screen frame]; // TODO(oshima): Implement ID and Observer. gfx::Display display(0, gfx::Rect(NSRectToCGRect(frame))); NSRect visible_frame = [screen visibleFrame]; + NSScreen* primary = [[NSScreen screens] objectAtIndex:0]; // Convert work area's coordinate systems. - if (is_primary) { + if ([screen isEqual:primary]) { gfx::Rect work_area = gfx::Rect(NSRectToCGRect(visible_frame)); work_area.set_y(frame.size.height - visible_frame.origin.y - visible_frame.size.height); @@ -96,10 +99,15 @@ class ScreenMac : public gfx::Screen { } virtual int GetNumDisplays() const OVERRIDE { - // Don't just return the number of online displays. It includes displays - // that mirror other displays, which are not desired in the count. It's + return GetAllDisplays().size(); + + } + + virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE { + // Don't just return all online displays. This would include displays + // that mirror other displays, which are not desired in this list. It's // tempting to use the count returned by CGGetActiveDisplayList, but active - // displays exclude sleeping displays, and those are desired in the count. + // displays exclude sleeping displays, and those are desired. // It would be ridiculous to have this many displays connected, but // CGDirectDisplayID is just an integer, so supporting up to this many @@ -109,29 +117,39 @@ class ScreenMac : public gfx::Screen { if (CGGetOnlineDisplayList(arraysize(online_displays), online_displays, &online_display_count) != kCGErrorSuccess) { - // 1 is a reasonable assumption. - return 1; + return std::vector<gfx::Display>(1, GetPrimaryDisplay()); } - int display_count = 0; + typedef std::map<int64, NSScreen*> ScreenIdsToScreensMap; + ScreenIdsToScreensMap screen_ids_to_screens; + for (NSScreen* screen in [NSScreen screens]) { + NSDictionary* screen_device_description = [screen deviceDescription]; + int64 screen_id = [[screen_device_description + objectForKey:@"NSScreenNumber"] unsignedIntValue]; + screen_ids_to_screens[screen_id] = screen; + } + + std::vector<gfx::Display> displays; for (CGDisplayCount online_display_index = 0; online_display_index < online_display_count; ++online_display_index) { CGDirectDisplayID online_display = online_displays[online_display_index]; if (CGDisplayMirrorsDisplay(online_display) == kCGNullDirectDisplay) { - // If this display doesn't mirror any other, include it in the count. + // If this display doesn't mirror any other, include it in the list. // The primary display in a mirrored set will be counted, but those that // mirror it will not be. - ++display_count; + ScreenIdsToScreensMap::iterator foundScreen = + screen_ids_to_screens.find(online_display); + if (foundScreen != screen_ids_to_screens.end()) { + displays.push_back(GetDisplayForScreen(foundScreen->second)); + } } } - return display_count; - } + if (!displays.size()) + return std::vector<gfx::Display>(1, GetPrimaryDisplay()); - virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE { - NOTIMPLEMENTED(); - return std::vector<gfx::Display>(1, GetPrimaryDisplay()); + return displays; } virtual gfx::Display GetDisplayNearestWindow( @@ -140,7 +158,9 @@ class ScreenMac : public gfx::Screen { if (!window) return GetPrimaryDisplay(); NSScreen* match_screen = [window screen]; - return GetDisplayForScreen(match_screen, false /* may not be primary */); + if (!match_screen) + return GetPrimaryDisplay(); + return GetDisplayForScreen(match_screen); } virtual gfx::Display GetDisplayNearestPoint( @@ -152,7 +172,7 @@ class ScreenMac : public gfx::Screen { ns_point.y = NSMaxY([primary frame]) - ns_point.y; for (NSScreen* screen in screens) { if (NSMouseInRect(ns_point, [screen frame], NO)) - return GetDisplayForScreen(screen, screen == primary); + return GetDisplayForScreen(screen); } return GetPrimaryDisplay(); } @@ -161,7 +181,7 @@ class ScreenMac : public gfx::Screen { virtual gfx::Display GetDisplayMatching( const gfx::Rect& match_rect) const OVERRIDE { NSScreen* match_screen = GetMatchingScreen(match_rect); - return GetDisplayForScreen(match_screen, false /* may not be primary */); + return GetDisplayForScreen(match_screen); } // Returns the primary display. @@ -169,7 +189,7 @@ class ScreenMac : public gfx::Screen { // Primary display is defined as the display with the menubar, // which is always at index 0. NSScreen* primary = [[NSScreen screens] objectAtIndex:0]; - gfx::Display display = GetDisplayForScreen(primary, true /* primary */); + gfx::Display display = GetDisplayForScreen(primary); return display; } diff --git a/chromium/ui/gfx/screen_type_delegate.h b/chromium/ui/gfx/screen_type_delegate.h index 12e8d90939d..4d9f116aedd 100644 --- a/chromium/ui/gfx/screen_type_delegate.h +++ b/chromium/ui/gfx/screen_type_delegate.h @@ -9,7 +9,7 @@ namespace gfx { -enum UI_EXPORT ScreenType { +enum GFX_EXPORT ScreenType { SCREEN_TYPE_NATIVE = 0, #if defined(OS_CHROMEOS) SCREEN_TYPE_ALTERNATE = SCREEN_TYPE_NATIVE, @@ -19,7 +19,7 @@ enum UI_EXPORT ScreenType { SCREEN_TYPE_LAST = SCREEN_TYPE_ALTERNATE, }; -class UI_EXPORT ScreenTypeDelegate { +class GFX_EXPORT ScreenTypeDelegate { public: virtual ~ScreenTypeDelegate() {} diff --git a/chromium/ui/gfx/screen_win.h b/chromium/ui/gfx/screen_win.h index a9fb7f518ff..7b1ea4c7bcc 100644 --- a/chromium/ui/gfx/screen_win.h +++ b/chromium/ui/gfx/screen_win.h @@ -11,7 +11,7 @@ namespace gfx { -class UI_EXPORT ScreenWin : public gfx::Screen { +class GFX_EXPORT ScreenWin : public gfx::Screen { public: ScreenWin(); virtual ~ScreenWin(); diff --git a/chromium/ui/gfx/scrollbar_size.h b/chromium/ui/gfx/scrollbar_size.h index d11774d17a7..bfea069af74 100644 --- a/chromium/ui/gfx/scrollbar_size.h +++ b/chromium/ui/gfx/scrollbar_size.h @@ -12,7 +12,7 @@ namespace gfx { // This should return the thickness, in pixels, of a scrollbar in web content. // This needs to match the values in WebCore's // ScrollbarThemeChromiumXXX.cpp::scrollbarThickness(). -UI_EXPORT int scrollbar_size(); +GFX_EXPORT int scrollbar_size(); } // namespace gfx diff --git a/chromium/ui/gfx/selection_model.h b/chromium/ui/gfx/selection_model.h index 0b811d1c5ce..d509e898a99 100644 --- a/chromium/ui/gfx/selection_model.h +++ b/chromium/ui/gfx/selection_model.h @@ -56,7 +56,7 @@ enum LogicalCursorDirection { // is given by a "caret affinity" which is either CURSOR_BACKWARD (indicating // the trailing half of the 'c' in this case) or CURSOR_FORWARD (indicating // the leading half of the 'D'). -class UI_EXPORT SelectionModel { +class GFX_EXPORT SelectionModel { public: // Create a default SelectionModel to be overwritten later. SelectionModel(); diff --git a/chromium/ui/gfx/sequential_id_generator.cc b/chromium/ui/gfx/sequential_id_generator.cc new file mode 100644 index 00000000000..7d905c7dbc5 --- /dev/null +++ b/chromium/ui/gfx/sequential_id_generator.cc @@ -0,0 +1,82 @@ +// 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/sequential_id_generator.h" + +#include "base/logging.h" + +namespace { + +// Removes |key| from |first|, and |first[key]| from |second|. +template<typename T> +void Remove(uint32 key, T* first, T* second) { + typename T::iterator iter = first->find(key); + if (iter == first->end()) + return; + + uint32 second_key = iter->second; + first->erase(iter); + + iter = second->find(second_key); + DCHECK(iter != second->end()); + second->erase(iter); +} + +} // namespace + +namespace ui { + +SequentialIDGenerator::SequentialIDGenerator(uint32 min_id) + : min_id_(min_id), + min_available_id_(min_id) { +} + +SequentialIDGenerator::~SequentialIDGenerator() { +} + +uint32 SequentialIDGenerator::GetGeneratedID(uint32 number) { + IDMap::iterator find = number_to_id_.find(number); + if (find != number_to_id_.end()) + return find->second; + + int id = GetNextAvailableID(); + number_to_id_.insert(std::make_pair(number, id)); + id_to_number_.insert(std::make_pair(id, number)); + return id; +} + +bool SequentialIDGenerator::HasGeneratedIDFor(uint32 number) const { + return number_to_id_.find(number) != number_to_id_.end(); +} + +void SequentialIDGenerator::ReleaseGeneratedID(uint32 id) { + UpdateNextAvailableIDAfterRelease(id); + Remove(id, &id_to_number_, &number_to_id_); +} + +void SequentialIDGenerator::ReleaseNumber(uint32 number) { + DCHECK_GT(number_to_id_.count(number), 0U); + UpdateNextAvailableIDAfterRelease(number_to_id_[number]); + Remove(number, &number_to_id_, &id_to_number_); +} + +uint32 SequentialIDGenerator::GetNextAvailableID() { + const uint32 kMaxID = 128; + while (id_to_number_.count(min_available_id_) > 0 && + min_available_id_ < kMaxID) { + ++min_available_id_; + } + if (min_available_id_ >= kMaxID) + min_available_id_ = min_id_; + return min_available_id_; +} + +void SequentialIDGenerator::UpdateNextAvailableIDAfterRelease(uint32 id) { + if (id < min_available_id_) { + min_available_id_ = id; + DCHECK_GE(min_available_id_, min_id_); + } +} + +} // namespace ui diff --git a/chromium/ui/gfx/sequential_id_generator.h b/chromium/ui/gfx/sequential_id_generator.h new file mode 100644 index 00000000000..e277a1562b1 --- /dev/null +++ b/chromium/ui/gfx/sequential_id_generator.h @@ -0,0 +1,60 @@ +// 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_SEQUENTIAL_ID_GENERATOR_H_ +#define UI_GFX_SEQUENTIAL_ID_GENERATOR_H_ + +#include <map> + +#include "base/basictypes.h" +#include "base/containers/hash_tables.h" +#include "ui/gfx/gfx_export.h" + +namespace ui { + +// This is used to generate a series of sequential ID numbers in a way that a +// new ID is always the lowest possible ID in the sequence. +class GFX_EXPORT SequentialIDGenerator { + public: + // Creates a new generator with the specified lower bound for the IDs. + explicit SequentialIDGenerator(uint32 min_id); + ~SequentialIDGenerator(); + + // Generates a unique ID to represent |number|. The generated ID is the + // smallest available ID greater than or equal to the |min_id| specified + // during creation of the generator. + uint32 GetGeneratedID(uint32 number); + + // Checks to see if the generator currently has a unique ID generated for + // |number|. + bool HasGeneratedIDFor(uint32 number) const; + + // Removes the generated ID |id| from the internal mapping. Since the ID is + // no longer mapped to any number, subsequent calls to |GetGeneratedID()| can + // use this ID. + void ReleaseGeneratedID(uint32 id); + + // Removes the ID previously generated for |number| by calling + // |GetGeneratedID()|. + void ReleaseNumber(uint32 number); + + private: + typedef base::hash_map<uint32, uint32> IDMap; + + uint32 GetNextAvailableID(); + + void UpdateNextAvailableIDAfterRelease(uint32 id); + + IDMap number_to_id_; + IDMap id_to_number_; + + uint32 min_id_; + uint32 min_available_id_; + + DISALLOW_COPY_AND_ASSIGN(SequentialIDGenerator); +}; + +} // namespace ui + +#endif // UI_GFX_SEQUENTIAL_ID_GENERATOR_H_ diff --git a/chromium/ui/gfx/sequential_id_generator_unittest.cc b/chromium/ui/gfx/sequential_id_generator_unittest.cc new file mode 100644 index 00000000000..7a07f90ff05 --- /dev/null +++ b/chromium/ui/gfx/sequential_id_generator_unittest.cc @@ -0,0 +1,62 @@ +// 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/sequential_id_generator.h" + +#include "base/logging.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace ui { + +typedef testing::Test SequentialIDGeneratorTest; + +TEST(SequentialIDGeneratorTest, AddRemove) { + const uint32 kMinID = 2; + SequentialIDGenerator generator(kMinID); + + EXPECT_EQ(2U, generator.GetGeneratedID(45)); + EXPECT_EQ(3U, generator.GetGeneratedID(23)); + EXPECT_EQ(2U, generator.GetGeneratedID(45)); + EXPECT_TRUE(generator.HasGeneratedIDFor(45)); + EXPECT_TRUE(generator.HasGeneratedIDFor(23)); + + generator.ReleaseGeneratedID(2); + EXPECT_FALSE(generator.HasGeneratedIDFor(45)); + EXPECT_TRUE(generator.HasGeneratedIDFor(23)); + EXPECT_EQ(3U, generator.GetGeneratedID(23)); + + EXPECT_FALSE(generator.HasGeneratedIDFor(1)); + EXPECT_EQ(2U, generator.GetGeneratedID(1)); + EXPECT_TRUE(generator.HasGeneratedIDFor(1)); + + generator.ReleaseGeneratedID(3); + EXPECT_EQ(3U, generator.GetGeneratedID(45)); + EXPECT_TRUE(generator.HasGeneratedIDFor(45)); + + generator.ReleaseNumber(45); + EXPECT_FALSE(generator.HasGeneratedIDFor(45)); +} + +TEST(SequentialIDGeneratorTest, RemoveMultipleNumbers) { + const uint32 kMinID = 4; + SequentialIDGenerator generator(kMinID); + + EXPECT_EQ(4U, generator.GetGeneratedID(45)); + EXPECT_EQ(5U, generator.GetGeneratedID(55)); + EXPECT_EQ(6U, generator.GetGeneratedID(15)); + + generator.ReleaseNumber(45); + EXPECT_FALSE(generator.HasGeneratedIDFor(45)); + generator.ReleaseNumber(15); + EXPECT_FALSE(generator.HasGeneratedIDFor(15)); + + EXPECT_EQ(5U, generator.GetGeneratedID(55)); + EXPECT_EQ(4U, generator.GetGeneratedID(12)); + + generator.ReleaseNumber(12); + generator.ReleaseNumber(55); + EXPECT_EQ(4U, generator.GetGeneratedID(0)); +} + +} // namespace ui diff --git a/chromium/ui/gfx/shadow_value.h b/chromium/ui/gfx/shadow_value.h index 46d84b4be3f..60b601e63bd 100644 --- a/chromium/ui/gfx/shadow_value.h +++ b/chromium/ui/gfx/shadow_value.h @@ -21,7 +21,7 @@ typedef std::vector<ShadowValue> ShadowValues; // ShadowValue encapsulates parameters needed to define a shadow, including the // shadow's offset, blur amount and color. -class UI_EXPORT ShadowValue { +class GFX_EXPORT ShadowValue { public: ShadowValue(); ShadowValue(const gfx::Point& offset, double blur, SkColor color); diff --git a/chromium/ui/gfx/size.h b/chromium/ui/gfx/size.h index c2340ebce63..c96f5897f3b 100644 --- a/chromium/ui/gfx/size.h +++ b/chromium/ui/gfx/size.h @@ -23,7 +23,7 @@ typedef struct tagSIZE SIZE; namespace gfx { // A size has width and height values. -class UI_EXPORT Size : public SizeBase<Size, int> { +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) {} diff --git a/chromium/ui/gfx/size_base.h b/chromium/ui/gfx/size_base.h index 72d47d2c37b..c8349dc4b77 100644 --- a/chromium/ui/gfx/size_base.h +++ b/chromium/ui/gfx/size_base.h @@ -11,7 +11,7 @@ namespace gfx { // A size has width and height values. template<typename Class, typename Type> -class UI_EXPORT SizeBase { +class GFX_EXPORT SizeBase { public: Type width() const { return width_; } Type height() const { return height_; } diff --git a/chromium/ui/gfx/size_conversions.h b/chromium/ui/gfx/size_conversions.h index f642c4cc7cf..af68195b55b 100644 --- a/chromium/ui/gfx/size_conversions.h +++ b/chromium/ui/gfx/size_conversions.h @@ -11,13 +11,13 @@ namespace gfx { // Returns a Size with each component from the input SizeF floored. -UI_EXPORT Size ToFlooredSize(const SizeF& size); +GFX_EXPORT Size ToFlooredSize(const SizeF& size); // Returns a Size with each component from the input SizeF ceiled. -UI_EXPORT Size ToCeiledSize(const SizeF& size); +GFX_EXPORT Size ToCeiledSize(const SizeF& size); // Returns a Size with each component from the input SizeF rounded. -UI_EXPORT Size ToRoundedSize(const SizeF& size); +GFX_EXPORT Size ToRoundedSize(const SizeF& size); } // namespace gfx diff --git a/chromium/ui/gfx/size_f.h b/chromium/ui/gfx/size_f.h index ee90189f7d9..b9065273c8e 100644 --- a/chromium/ui/gfx/size_f.h +++ b/chromium/ui/gfx/size_f.h @@ -14,7 +14,7 @@ namespace gfx { // A floating version of gfx::Size. -class UI_EXPORT SizeF : public SizeBase<SizeF, float> { +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) {} @@ -39,7 +39,7 @@ inline bool operator!=(const SizeF& lhs, const SizeF& rhs) { return !(lhs == rhs); } -UI_EXPORT SizeF ScaleSize(const SizeF& p, float x_scale, float y_scale); +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); diff --git a/chromium/ui/gfx/skbitmap_operations.cc b/chromium/ui/gfx/skbitmap_operations.cc index bcc27238d57..c89153692a4 100644 --- a/chromium/ui/gfx/skbitmap_operations.cc +++ b/chromium/ui/gfx/skbitmap_operations.cc @@ -560,10 +560,9 @@ SkBitmap SkBitmapOperations::CreateHSLShiftedBitmap( SkBitmap shifted; shifted.setConfig(SkBitmap::kARGB_8888_Config, bitmap.width(), - bitmap.height(), 0); + bitmap.height()); shifted.allocPixels(); shifted.eraseARGB(0, 0, 0, 0); - shifted.setIsOpaque(false); SkAutoLockPixels lock_bitmap(bitmap); SkAutoLockPixels lock_shifted(shifted); @@ -704,7 +703,8 @@ SkBitmap SkBitmapOperations::UnPreMultiply(const SkBitmap& bitmap) { return bitmap; SkBitmap opaque_bitmap; - opaque_bitmap.setConfig(bitmap.config(), bitmap.width(), bitmap.height()); + opaque_bitmap.setConfig(bitmap.config(), bitmap.width(), bitmap.height(), + 0, kOpaque_SkAlphaType); opaque_bitmap.allocPixels(); { @@ -720,7 +720,6 @@ SkBitmap SkBitmapOperations::UnPreMultiply(const SkBitmap& bitmap) { } } - opaque_bitmap.setIsOpaque(true); return opaque_bitmap; } diff --git a/chromium/ui/gfx/skbitmap_operations.h b/chromium/ui/gfx/skbitmap_operations.h index 3a0d3c97504..fd25d5efc97 100644 --- a/chromium/ui/gfx/skbitmap_operations.h +++ b/chromium/ui/gfx/skbitmap_operations.h @@ -17,7 +17,7 @@ class Size; class SkBitmap; -class UI_EXPORT SkBitmapOperations { +class GFX_EXPORT SkBitmapOperations { public: // Enum for use in rotating images (must be in 90 degree increments), // see: Rotate. diff --git a/chromium/ui/gfx/skbitmap_operations_unittest.cc b/chromium/ui/gfx/skbitmap_operations_unittest.cc index bfb208cae2a..4e488aa2c45 100644 --- a/chromium/ui/gfx/skbitmap_operations_unittest.cc +++ b/chromium/ui/gfx/skbitmap_operations_unittest.cc @@ -63,10 +63,9 @@ SkBitmap ReferenceCreateHSLShiftedBitmap( color_utils::HSL hsl_shift) { SkBitmap shifted; shifted.setConfig(SkBitmap::kARGB_8888_Config, bitmap.width(), - bitmap.height(), 0); + bitmap.height()); shifted.allocPixels(); shifted.eraseARGB(0, 0, 0, 0); - shifted.setIsOpaque(false); SkAutoLockPixels lock_bitmap(bitmap); SkAutoLockPixels lock_shifted(shifted); diff --git a/chromium/ui/gfx/skia_util.cc b/chromium/ui/gfx/skia_util.cc index 50092ab13b6..bb7cde7b4ba 100644 --- a/chromium/ui/gfx/skia_util.cc +++ b/chromium/ui/gfx/skia_util.cc @@ -50,15 +50,15 @@ RectF SkRectToRectF(const SkRect& rect) { void TransformToFlattenedSkMatrix(const gfx::Transform& transform, SkMatrix* flattened) { // Convert from 4x4 to 3x3 by dropping the third row and column. - flattened->set(0, SkDoubleToScalar(transform.matrix().getDouble(0, 0))); - flattened->set(1, SkDoubleToScalar(transform.matrix().getDouble(0, 1))); - flattened->set(2, SkDoubleToScalar(transform.matrix().getDouble(0, 3))); - flattened->set(3, SkDoubleToScalar(transform.matrix().getDouble(1, 0))); - flattened->set(4, SkDoubleToScalar(transform.matrix().getDouble(1, 1))); - flattened->set(5, SkDoubleToScalar(transform.matrix().getDouble(1, 3))); - flattened->set(6, SkDoubleToScalar(transform.matrix().getDouble(3, 0))); - flattened->set(7, SkDoubleToScalar(transform.matrix().getDouble(3, 1))); - flattened->set(8, SkDoubleToScalar(transform.matrix().getDouble(3, 3))); + flattened->set(0, SkMScalarToScalar(transform.matrix().get(0, 0))); + flattened->set(1, SkMScalarToScalar(transform.matrix().get(0, 1))); + flattened->set(2, SkMScalarToScalar(transform.matrix().get(0, 3))); + flattened->set(3, SkMScalarToScalar(transform.matrix().get(1, 0))); + flattened->set(4, SkMScalarToScalar(transform.matrix().get(1, 1))); + flattened->set(5, SkMScalarToScalar(transform.matrix().get(1, 3))); + flattened->set(6, SkMScalarToScalar(transform.matrix().get(3, 0))); + flattened->set(7, SkMScalarToScalar(transform.matrix().get(3, 1))); + flattened->set(8, SkMScalarToScalar(transform.matrix().get(3, 3))); } skia::RefPtr<SkShader> CreateImageRepShader(const gfx::ImageSkiaRep& image_rep, @@ -68,7 +68,7 @@ skia::RefPtr<SkShader> CreateImageRepShader(const gfx::ImageSkiaRep& image_rep, 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.GetScale()); + SkScalar bitmap_scale = SkFloatToScalar(image_rep.scale()); // Unscale matrix by |bitmap_scale| such that the bitmap is drawn at the // correct density. diff --git a/chromium/ui/gfx/skia_util.h b/chromium/ui/gfx/skia_util.h index 592ff5f2f66..92c886a4309 100644 --- a/chromium/ui/gfx/skia_util.h +++ b/chromium/ui/gfx/skia_util.h @@ -26,14 +26,14 @@ class ShadowValue; class Transform; // Convert between Skia and gfx rect types. -UI_EXPORT SkRect RectToSkRect(const Rect& rect); -UI_EXPORT SkIRect RectToSkIRect(const Rect& rect); -UI_EXPORT Rect SkIRectToRect(const SkIRect& rect); -UI_EXPORT SkRect RectFToSkRect(const RectF& rect); -UI_EXPORT RectF SkRectToRectF(const SkRect& rect); +GFX_EXPORT SkRect RectToSkRect(const Rect& rect); +GFX_EXPORT SkIRect RectToSkIRect(const Rect& rect); +GFX_EXPORT Rect SkIRectToRect(const SkIRect& rect); +GFX_EXPORT SkRect RectFToSkRect(const RectF& rect); +GFX_EXPORT RectF SkRectToRectF(const SkRect& rect); -UI_EXPORT void TransformToFlattenedSkMatrix(const gfx::Transform& transform, - SkMatrix* flattened); +GFX_EXPORT void TransformToFlattenedSkMatrix(const gfx::Transform& transform, + SkMatrix* flattened); // Creates a bitmap shader for the image rep with the image rep's scale factor. // Sets the created shader's local matrix such that it displays the image rep at @@ -42,32 +42,32 @@ UI_EXPORT void TransformToFlattenedSkMatrix(const gfx::Transform& transform, // TODO(pkotwicz): Allow shader's local matrix to be changed after the shader // is created. // -UI_EXPORT skia::RefPtr<SkShader> CreateImageRepShader( +GFX_EXPORT skia::RefPtr<SkShader> CreateImageRepShader( const gfx::ImageSkiaRep& image_rep, SkShader::TileMode tile_mode, const SkMatrix& local_matrix); // Creates a vertical gradient shader. The caller owns the shader. // Example usage to avoid leaks: -UI_EXPORT skia::RefPtr<SkShader> CreateGradientShader(int start_point, - int end_point, - SkColor start_color, - SkColor end_color); +GFX_EXPORT skia::RefPtr<SkShader> CreateGradientShader(int start_point, + int end_point, + SkColor start_color, + SkColor end_color); // Creates a draw looper to generate |shadows|. The caller owns the draw looper. // NULL is returned if |shadows| is empty since no draw looper is needed in // this case. -UI_EXPORT skia::RefPtr<SkDrawLooper> CreateShadowDrawLooper( +GFX_EXPORT skia::RefPtr<SkDrawLooper> CreateShadowDrawLooper( const std::vector<ShadowValue>& shadows); // Returns true if the two bitmaps contain the same pixels. -UI_EXPORT bool BitmapsAreEqual(const SkBitmap& bitmap1, - const SkBitmap& bitmap2); +GFX_EXPORT bool BitmapsAreEqual(const SkBitmap& bitmap1, + const SkBitmap& bitmap2); // Converts Skia ARGB format pixels in |skia| to RGBA. -UI_EXPORT void ConvertSkiaToRGBA(const unsigned char* skia, - int pixel_width, - unsigned char* rgba); +GFX_EXPORT void ConvertSkiaToRGBA(const unsigned char* skia, + int pixel_width, + unsigned char* rgba); } // namespace gfx diff --git a/chromium/ui/gfx/skia_utils_gtk.h b/chromium/ui/gfx/skia_utils_gtk.h index abe397722ac..6b74da246ea 100644 --- a/chromium/ui/gfx/skia_utils_gtk.h +++ b/chromium/ui/gfx/skia_utils_gtk.h @@ -13,10 +13,10 @@ typedef struct _GdkColor GdkColor; namespace gfx { // Converts GdkColors to the ARGB layout Skia expects. -UI_EXPORT SkColor GdkColorToSkColor(GdkColor color); +GFX_EXPORT SkColor GdkColorToSkColor(GdkColor color); // Converts ARGB to GdkColor. -UI_EXPORT GdkColor SkColorToGdkColor(SkColor color); +GFX_EXPORT GdkColor SkColorToGdkColor(SkColor color); } // namespace gfx diff --git a/chromium/ui/gfx/switches.h b/chromium/ui/gfx/switches.h index e3cd9e7db85..c5629f249c4 100644 --- a/chromium/ui/gfx/switches.h +++ b/chromium/ui/gfx/switches.h @@ -9,10 +9,10 @@ namespace switches { -UI_EXPORT extern const char kEnableBrowserTextSubpixelPositioning[]; -UI_EXPORT extern const char kEnableWebkitTextSubpixelPositioning[]; -UI_EXPORT extern const char kForceDeviceScaleFactor[]; -UI_EXPORT extern const char kHighDPISupport[]; +GFX_EXPORT extern const char kEnableBrowserTextSubpixelPositioning[]; +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.h b/chromium/ui/gfx/sys_color_change_listener.h index db3f9df74cc..31afd0cc49f 100644 --- a/chromium/ui/gfx/sys_color_change_listener.h +++ b/chromium/ui/gfx/sys_color_change_listener.h @@ -15,10 +15,10 @@ namespace gfx { // only true if the system has high-contrast mode enabled and and is using a // light-on-dark color scheme. To be notified when this status changes, use // ScopedSysColorChangeListener, below. -UI_EXPORT bool IsInvertedColorScheme(); +GFX_EXPORT bool IsInvertedColorScheme(); // Interface for classes that want to listen to system color changes. -class UI_EXPORT SysColorChangeListener { +class GFX_EXPORT SysColorChangeListener { public: virtual void OnSysColorChange() = 0; @@ -28,7 +28,7 @@ class UI_EXPORT SysColorChangeListener { // Create an instance of this class in any object that wants to listen // for system color changes. -class UI_EXPORT ScopedSysColorChangeListener { +class GFX_EXPORT ScopedSysColorChangeListener { public: explicit ScopedSysColorChangeListener(SysColorChangeListener* listener); ~ScopedSysColorChangeListener(); diff --git a/chromium/ui/gfx/text_constants.h b/chromium/ui/gfx/text_constants.h index cafeab4669b..4ac788e6109 100644 --- a/chromium/ui/gfx/text_constants.h +++ b/chromium/ui/gfx/text_constants.h @@ -28,16 +28,6 @@ enum HorizontalAlignment { ALIGN_RIGHT, }; -// Vertical text alignment modes. -enum VerticalAlignment { - // Align the text's top edge with that of its display area. - ALIGN_TOP = 0, - // Align the text's center with that of its display area. - ALIGN_VCENTER, - // Align the text's bottom edge with that of its display area. - ALIGN_BOTTOM, -}; - // The directionality modes used to determine the base text direction. enum DirectionalityMode { // Use the first strong character's direction. diff --git a/chromium/ui/gfx/text_elider.cc b/chromium/ui/gfx/text_elider.cc index bc4eb3bb858..5b9469614f2 100644 --- a/chromium/ui/gfx/text_elider.cc +++ b/chromium/ui/gfx/text_elider.cc @@ -34,16 +34,16 @@ namespace gfx { // U+2026 in utf8 const char kEllipsis[] = "\xE2\x80\xA6"; -const char16 kEllipsisUTF16[] = { 0x2026, 0 }; -const char16 kForwardSlash = '/'; +const base::char16 kEllipsisUTF16[] = { 0x2026, 0 }; +const base::char16 kForwardSlash = '/'; namespace { // Helper class to split + elide text, while respecting UTF16 surrogate pairs. class StringSlicer { public: - StringSlicer(const string16& text, - const string16& ellipsis, + StringSlicer(const base::string16& text, + const base::string16& ellipsis, bool elide_in_middle) : text_(text), ellipsis_(ellipsis), @@ -55,8 +55,9 @@ class StringSlicer { // 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. - string16 CutString(size_t length, bool insert_ellipsis) { - const string16 ellipsis_text = insert_ellipsis ? ellipsis_ : string16(); + 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; @@ -90,10 +91,10 @@ class StringSlicer { } // The text to be sliced. - const string16& text_; + const base::string16& text_; // Ellipsis string to use. - const string16& ellipsis_; + const base::string16& ellipsis_; // If true, the middle of the string will be elided. bool elide_in_middle_; @@ -103,12 +104,13 @@ class StringSlicer { // Build a path from the first |num_components| elements in |path_elements|. // Prepends |path_prefix|, appends |filename|, inserts ellipsis if appropriate. -string16 BuildPathFromComponents(const string16& path_prefix, - const std::vector<string16>& path_elements, - const string16& filename, - size_t num_components) { +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. - string16 path = path_prefix; + base::string16 path = path_prefix; // Build path from first |num_components| elements. for (size_t j = 0; j < num_components; ++j) @@ -116,7 +118,7 @@ string16 BuildPathFromComponents(const string16& path_prefix, // Add |filename|, ellipsis if necessary. if (num_components != (path_elements.size() - 1)) - path += string16(kEllipsisUTF16) + kForwardSlash; + path += base::string16(kEllipsisUTF16) + kForwardSlash; path += filename; return path; @@ -125,32 +127,33 @@ string16 BuildPathFromComponents(const string16& path_prefix, // 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. -string16 ElideComponentizedPath(const string16& url_path_prefix, - const std::vector<string16>& url_path_elements, - const string16& url_filename, - const string16& url_query, - const gfx::FontList& font_list, - int available_pixel_width) { +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) { - string16 elided_path = BuildPathFromComponents(url_path_prefix, + base::string16 elided_path = BuildPathFromComponents(url_path_prefix, url_path_elements, url_filename, i); - if (available_pixel_width >= gfx::GetStringWidth(elided_path, font_list)) + if (available_pixel_width >= GetStringWidthF(elided_path, font_list)) return ElideText(elided_path + url_query, font_list, available_pixel_width, ELIDE_AT_END); } - return string16(); + return base::string16(); } } // namespace -string16 ElideEmail(const string16& email, - const gfx::FontList& font_list, - int available_pixel_width) { - if (gfx::GetStringWidth(email, font_list) <= available_pixel_width) +base::string16 ElideEmail(const base::string16& email, + const FontList& font_list, + float available_pixel_width) { + if (GetStringWidthF(email, font_list) <= available_pixel_width) return email; // Split the email into its local-part (username) and domain-part. The email @@ -159,32 +162,32 @@ string16 ElideEmail(const string16& email, // symbol in the domain part of the email however so splitting at the last @ // symbol is safe. const size_t split_index = email.find_last_of('@'); - DCHECK_NE(split_index, string16::npos); - string16 username = email.substr(0, split_index); - string16 domain = email.substr(split_index + 1); + DCHECK_NE(split_index, base::string16::npos); + base::string16 username = email.substr(0, split_index); + base::string16 domain = email.substr(split_index + 1); DCHECK(!username.empty()); DCHECK(!domain.empty()); // Subtract the @ symbol from the available width as it is mandatory. - const string16 kAtSignUTF16 = ASCIIToUTF16("@"); - available_pixel_width -= gfx::GetStringWidth(kAtSignUTF16, font_list); + const base::string16 kAtSignUTF16 = ASCIIToUTF16("@"); + available_pixel_width -= GetStringWidthF(kAtSignUTF16, font_list); // Check whether eliding the domain is necessary: if eliding the username // is sufficient, the domain will not be elided. - const int full_username_width = gfx::GetStringWidth(username, font_list); - const int available_domain_width = + const float full_username_width = GetStringWidthF(username, font_list); + const float available_domain_width = available_pixel_width - std::min(full_username_width, - gfx::GetStringWidth(username.substr(0, 1) + kEllipsisUTF16, - font_list)); - if (gfx::GetStringWidth(domain, font_list) > available_domain_width) { + GetStringWidthF(username.substr(0, 1) + kEllipsisUTF16, + font_list)); + if (GetStringWidthF(domain, font_list) > available_domain_width) { // Elide the domain so that it only takes half of the available width. // Should the username not need all the width available in its half, the // domain will occupy the leftover width. // If |desired_domain_width| is greater than |available_domain_width|: the // minimal username elision allowed by the specifications will not fit; thus // |desired_domain_width| must be <= |available_domain_width| at all cost. - const int desired_domain_width = + const float desired_domain_width = std::min(available_domain_width, std::max(available_pixel_width - full_username_width, available_pixel_width / 2)); @@ -193,36 +196,30 @@ string16 ElideEmail(const string16& email, // 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) - return string16(kEllipsisUTF16); + return base::string16(kEllipsisUTF16); } // Fit the username in the remaining width (at this point the elided username // is guaranteed to fit with at least one character remaining given all the // precautions taken earlier). - available_pixel_width -= gfx::GetStringWidth(domain, font_list); + available_pixel_width -= GetStringWidthF(domain, font_list); username = ElideText(username, font_list, available_pixel_width, ELIDE_AT_END); return username + kAtSignUTF16 + domain; } -string16 ElideEmail(const string16& email, - const gfx::Font& font, - int available_pixel_width) { - return ElideEmail(email, gfx::FontList(font), available_pixel_width); -} - // 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. -string16 ElideUrl(const GURL& url, - const gfx::FontList& font_list, - int available_pixel_width, - const std::string& languages) { +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 string16 url_string = + const base::string16 url_string = net::FormatUrl(url, languages, net::kFormatUrlOmitAll, net::UnescapeRule::SPACES, &parsed, NULL, NULL); if (available_pixel_width <= 0) @@ -235,28 +232,28 @@ string16 ElideUrl(const GURL& url, // Now start eliding url_string to fit within available pixel width. // Fist pass - check to see whether entire url_string fits. - const int pixel_width_url_string = gfx::GetStringWidth(url_string, font_list); + 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; - string16 url_path_query_etc = url_string.substr(path_start_index); - string16 url_path = url_string.substr(path_start_index, 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 string16 url_minus_query = + const base::string16 url_minus_query = url_string.substr(0, path_start_index + path_len); - if (available_pixel_width >= gfx::GetStringWidth(url_minus_query, font_list)) + if (available_pixel_width >= GetStringWidthF(url_minus_query, font_list)) return ElideText(url_string, font_list, available_pixel_width, ELIDE_AT_END); // Get Host. - string16 url_host = UTF8ToUTF16(url.host()); + base::string16 url_host = UTF8ToUTF16(url.host()); // Get domain and registry information from the URL. - string16 url_domain = UTF8ToUTF16( + base::string16 url_domain = UTF8ToUTF16( net::registry_controlled_domains::GetDomainAndRegistry( url, net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES)); if (url_domain.empty()) @@ -269,11 +266,11 @@ string16 ElideUrl(const GURL& url, } // Get sub domain. - string16 url_subdomain; + base::string16 url_subdomain; const size_t domain_start_index = url_host.find(url_domain); - if (domain_start_index != string16::npos) + if (domain_start_index != base::string16::npos) url_subdomain = url_host.substr(0, domain_start_index); - const string16 kWwwPrefix = UTF8ToUTF16("www."); + const base::string16 kWwwPrefix = UTF8ToUTF16("www."); if ((url_subdomain == kWwwPrefix || url_subdomain.empty() || url.SchemeIsFile())) { url_subdomain.clear(); @@ -284,59 +281,59 @@ string16 ElideUrl(const GURL& url, // domain is now C: - this is a nice hack for eliding to work pleasantly. if (url.SchemeIsFile()) { // Split the path string using ":" - std::vector<string16> file_path_split; + 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 string16 kColon = UTF8ToUTF16(":"); + 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); } } // Second Pass - remove scheme - the rest fits. - const int pixel_width_url_host = gfx::GetStringWidth(url_host, font_list); - const int pixel_width_url_path = gfx::GetStringWidth(url_path_query_etc, - font_list); + 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 int pixel_width_url_domain = gfx::GetStringWidth(url_domain, font_list); - const int pixel_width_url_subdomain = gfx::GetStringWidth(url_subdomain, - font_list); + 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. - string16 url_query; - const int kPixelWidthDotsTrailer = gfx::GetStringWidth( - string16(kEllipsisUTF16), font_list); + 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 - gfx::GetStringWidth(url_query, font_list))) { + 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); } } // Parse url_path using '/'. - std::vector<string16> url_path_elements; + 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); - string16 url_filename; + 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 '/'. @@ -356,12 +353,13 @@ string16 ElideUrl(const GURL& url, } // Start eliding the path and replacing elements by ".../". - const string16 kEllipsisAndSlash = string16(kEllipsisUTF16) + kForwardSlash; - const int pixel_width_ellipsis_slash = gfx::GetStringWidth(kEllipsisAndSlash, - font_list); + const base::string16 kEllipsisAndSlash = + base::string16(kEllipsisUTF16) + kForwardSlash; + const float pixel_width_ellipsis_slash = + GetStringWidthF(kEllipsisAndSlash, font_list); // Check with both subdomain and domain. - string16 elided_path = + base::string16 elided_path = ElideComponentizedPath(url_subdomain + url_domain, url_path_elements, url_filename, url_query, font_list, available_pixel_width); @@ -373,7 +371,7 @@ string16 ElideUrl(const GURL& url, // 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. - string16 url_elided_domain = url_subdomain + url_domain; + 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; @@ -389,15 +387,15 @@ string16 ElideUrl(const GURL& url, } // Return elided domain/.../filename anyway. - string16 final_elided_url_string(url_elided_domain); - const int url_elided_domain_width = gfx::GetStringWidth(url_elided_domain, - font_list); + 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 + - gfx::GetStringWidth(ASCIIToUTF16("UV"), font_list)) { - final_elided_url_string += BuildPathFromComponents(string16(), + 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; @@ -407,80 +405,67 @@ string16 ElideUrl(const GURL& url, ELIDE_AT_END); } -string16 ElideUrl(const GURL& url, - const gfx::Font& font, - int available_pixel_width, - const std::string& languages) { - return ElideUrl(url, gfx::FontList(font), available_pixel_width, languages); -} - -string16 ElideFilename(const base::FilePath& filename, - const gfx::FontList& font_list, - int available_pixel_width) { +base::string16 ElideFilename(const base::FilePath& filename, + const FontList& font_list, + float available_pixel_width) { #if defined(OS_WIN) - string16 filename_utf16 = filename.value(); - string16 extension = filename.Extension(); - string16 rootname = filename.BaseName().RemoveExtension().value(); + base::string16 filename_utf16 = filename.value(); + base::string16 extension = filename.Extension(); + base::string16 rootname = filename.BaseName().RemoveExtension().value(); #elif defined(OS_POSIX) - string16 filename_utf16 = WideToUTF16(base::SysNativeMBToWide( + base::string16 filename_utf16 = WideToUTF16(base::SysNativeMBToWide( filename.value())); - string16 extension = WideToUTF16(base::SysNativeMBToWide( + base::string16 extension = WideToUTF16(base::SysNativeMBToWide( filename.Extension())); - string16 rootname = WideToUTF16(base::SysNativeMBToWide( + base::string16 rootname = WideToUTF16(base::SysNativeMBToWide( filename.BaseName().RemoveExtension().value())); #endif - const int full_width = gfx::GetStringWidth(filename_utf16, font_list); + const float full_width = GetStringWidthF(filename_utf16, font_list); if (full_width <= available_pixel_width) return base::i18n::GetDisplayStringInLTRDirectionality(filename_utf16); if (rootname.empty() || extension.empty()) { - const string16 elided_name = ElideText(filename_utf16, font_list, + const base::string16 elided_name = ElideText(filename_utf16, font_list, available_pixel_width, ELIDE_AT_END); return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); } - const int ext_width = gfx::GetStringWidth(extension, font_list); - const int root_width = gfx::GetStringWidth(rootname, font_list); + const float ext_width = GetStringWidthF(extension, font_list); + const float root_width = GetStringWidthF(rootname, font_list); // We may have trimmed the path. if (root_width + ext_width <= available_pixel_width) { - const string16 elided_name = rootname + extension; + const base::string16 elided_name = rootname + extension; return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); } if (ext_width >= available_pixel_width) { - const string16 elided_name = ElideText(rootname + extension, font_list, - available_pixel_width, - ELIDE_IN_MIDDLE); + const base::string16 elided_name = ElideText( + rootname + extension, font_list, available_pixel_width, + ELIDE_IN_MIDDLE); return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); } - int available_root_width = available_pixel_width - ext_width; - string16 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); elided_name += extension; return base::i18n::GetDisplayStringInLTRDirectionality(elided_name); } -string16 ElideFilename(const base::FilePath& filename, - const gfx::Font& font, - int available_pixel_width) { - return ElideFilename(filename, gfx::FontList(font), available_pixel_width); -} - -string16 ElideText(const string16& text, - const gfx::FontList& font_list, - int available_pixel_width, - ElideBehavior elide_behavior) { +base::string16 ElideText(const base::string16& text, + const FontList& font_list, + float available_pixel_width, + ElideBehavior elide_behavior) { if (text.empty()) return text; - const int current_text_pixel_width = gfx::GetStringWidth(text, font_list); + 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 string16 ellipsis = string16(kEllipsisUTF16); + const base::string16 ellipsis = base::string16(kEllipsisUTF16); StringSlicer slicer(text, ellipsis, elide_in_middle); // Pango will return 0 width for absurdly long strings. Cut the string in @@ -492,7 +477,7 @@ string16 ElideText(const string16& text, // (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 string16 cut = slicer.CutString(text.length() / 2, false); + const base::string16 cut = slicer.CutString(text.length() / 2, false); return ElideText(cut, font_list, available_pixel_width, elide_behavior); } @@ -500,8 +485,8 @@ string16 ElideText(const string16& text, return text; if (insert_ellipsis && - gfx::GetStringWidth(ellipsis, font_list) > available_pixel_width) - return string16(); + GetStringWidthF(ellipsis, font_list) > available_pixel_width) + return base::string16(); // Use binary search to compute the elided text. size_t lo = 0; @@ -510,8 +495,8 @@ string16 ElideText(const string16& text, 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 // handle kerning/ligatures/etc. correctly. - const string16 cut = slicer.CutString(guess, insert_ellipsis); - const int guess_length = gfx::GetStringWidth(cut, font_list); + 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) { @@ -527,18 +512,17 @@ string16 ElideText(const string16& text, return slicer.CutString(guess, insert_ellipsis); } -string16 ElideText(const string16& text, - const gfx::Font& font, - int available_pixel_width, - ElideBehavior elide_behavior) { - return ElideText(text, gfx::FontList(font), available_pixel_width, - elide_behavior); +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_); - string16 host_minus_www = net::StripWWW(sort_host_); + base::string16 host_minus_www = net::StripWWW(sort_host_); url_parse::Parsed parsed; display_url_ = net::FormatUrl(url, languages, net::kFormatUrlOmitAll, @@ -570,8 +554,8 @@ int SortedDisplayURL::Compare(const SortedDisplayURL& other, return host_compare_result; // Hosts match, compare on the portion of the url after the host. - string16 path = this->AfterHost(); - string16 o_path = other.AfterHost(); + 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()), @@ -596,16 +580,17 @@ int SortedDisplayURL::Compare(const SortedDisplayURL& other, return display_url_compare_result; } -string16 SortedDisplayURL::AfterHost() const { +base::string16 SortedDisplayURL::AfterHost() const { const size_t slash_index = display_url_.find(sort_host_, prefix_end_); - if (slash_index == string16::npos) { + if (slash_index == base::string16::npos) { NOTREACHED(); - return string16(); + return base::string16(); } return display_url_.substr(slash_index + sort_host_.length()); } -bool ElideString(const string16& input, int max_len, string16* output) { +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) { output->assign(input); @@ -650,7 +635,7 @@ namespace { class RectangleString { public: RectangleString(size_t max_rows, size_t max_cols, - bool strict, string16 *output) + bool strict, base::string16 *output) : max_rows_(max_rows), max_cols_(max_cols), current_row_(0), @@ -667,7 +652,7 @@ class RectangleString { // AddString() may be called multiple times to concatenate together // multiple strings into the region (the current caller doesn't do // this, however). - void AddString(const string16& input); + void AddString(const base::string16& input); // Perform any deferred output processing. Must be called after the // last AddString() call has occurred. @@ -676,15 +661,15 @@ class RectangleString { private: // Add a line to the rectangular region at the current position, // either by itself or by breaking it into words. - void AddLine(const string16& line); + void AddLine(const base::string16& line); // Add a word to the rectangular region at the current position, // either by itself or by breaking it into characters. - void AddWord(const string16& word); + void AddWord(const base::string16& word); // Add text to the output string if the rectangular boundaries // have not been exceeded, advancing the current position. - void Append(const string16& string); + void Append(const base::string16& string); // Set the current position to the beginning of the next line. If // |output| is true, add a newline to the output string if the rectangular @@ -716,12 +701,12 @@ class RectangleString { bool suppressed_; // String onto which the output is accumulated. - string16* output_; + base::string16* output_; DISALLOW_COPY_AND_ASSIGN(RectangleString); }; -void RectangleString::AddString(const string16& input) { +void RectangleString::AddString(const base::string16& input) { base::i18n::BreakIterator lines(input, base::i18n::BreakIterator::BREAK_NEWLINE); if (lines.Init()) { @@ -740,7 +725,7 @@ bool RectangleString::Finalize() { return false; } -void RectangleString::AddLine(const string16& line) { +void RectangleString::AddLine(const base::string16& line) { if (line.length() < max_cols_) { Append(line); } else { @@ -758,7 +743,7 @@ void RectangleString::AddLine(const string16& line) { current_col_ = 0; } -void RectangleString::AddWord(const string16& word) { +void RectangleString::AddWord(const base::string16& word) { if (word.length() < max_cols_) { // Word can be made to fit, no need to fragment it. if (current_col_ + word.length() >= max_cols_) @@ -785,7 +770,7 @@ void RectangleString::AddWord(const string16& word) { } } -void RectangleString::Append(const string16& string) { +void RectangleString::Append(const base::string16& string) { if (current_row_ < max_rows_) output_->append(string); else @@ -809,11 +794,11 @@ void RectangleString::NewLine(bool output) { // can be broken into smaller methods sharing this state. class RectangleText { public: - RectangleText(const gfx::FontList& font_list, - int available_pixel_width, + RectangleText(const FontList& font_list, + float available_pixel_width, int available_pixel_height, WordWrapBehavior wrap_behavior, - std::vector<string16>* lines) + std::vector<base::string16>* lines) : font_list_(font_list), line_height_(font_list.GetHeight()), available_pixel_width_(available_pixel_width), @@ -834,7 +819,7 @@ class RectangleText { // AddString() may be called multiple times to concatenate together // multiple strings into the region (the current caller doesn't do // this, however). - void AddString(const string16& input); + void AddString(const base::string16& input); // Perform any deferred output processing. Must be called after the last // AddString() call has occured. Returns a combination of @@ -845,36 +830,36 @@ class RectangleText { private: // Add a line to the rectangular region at the current position, // either by itself or by breaking it into words. - void AddLine(const string16& line); + void AddLine(const base::string16& line); // Wrap the specified word across multiple lines. - int WrapWord(const string16& word); + int WrapWord(const base::string16& word); // Add a long word - wrapping, eliding or truncating per the wrap behavior. - int AddWordOverflow(const string16& word); + int AddWordOverflow(const base::string16& word); // Add a word to the rectangluar region at the current position. - int AddWord(const string16& word); + int AddWord(const base::string16& word); // Append the specified |text| to the current output line, incrementing the // running width by the specified amount. This is an optimization over // |AddToCurrentLine()| when |text_width| is already known. - void AddToCurrentLineWithWidth(const string16& text, int text_width); + void AddToCurrentLineWithWidth(const base::string16& text, float text_width); // Append the specified |text| to the current output line. - void AddToCurrentLine(const string16& text); + void AddToCurrentLine(const base::string16& text); // Set the current position to the beginning of the next line. bool NewLine(); // The font list used for measuring text width. - const gfx::FontList& font_list_; + const FontList& font_list_; // The height of each line of text. const int line_height_; // The number of pixels of available width in the rectangle. - const int available_pixel_width_; + const float available_pixel_width_; // The number of pixels of available height in the rectangle. const int available_pixel_height_; @@ -883,19 +868,19 @@ class RectangleText { const WordWrapBehavior wrap_behavior_; // The current running width. - int current_width_; + float current_width_; // The current running height. int current_height_; // The current line of text. - string16 current_line_; + base::string16 current_line_; // Indicates whether the last line ended with \n. bool last_line_ended_in_lf_; // The output vector of lines. - std::vector<string16>* lines_; + std::vector<base::string16>* lines_; // Indicates whether a word was so long that it had to be truncated or elided // to fit the available width. @@ -907,12 +892,12 @@ class RectangleText { DISALLOW_COPY_AND_ASSIGN(RectangleText); }; -void RectangleText::AddString(const string16& input) { +void RectangleText::AddString(const base::string16& input) { base::i18n::BreakIterator lines(input, base::i18n::BreakIterator::BREAK_NEWLINE); if (lines.Init()) { while (!insufficient_height_ && lines.Advance()) { - string16 line = lines.GetString(); + base::string16 line = lines.GetString(); // The BREAK_NEWLINE iterator will keep the trailing newline character, // except in the case of the last line, which may not have one. Remove // the newline character, if it exists. @@ -935,13 +920,13 @@ int RectangleText::Finalize() { lines_->pop_back(); } if (last_line_ended_in_lf_) - lines_->push_back(string16()); + lines_->push_back(base::string16()); return (insufficient_width_ ? INSUFFICIENT_SPACE_HORIZONTAL : 0) | (insufficient_height_ ? INSUFFICIENT_SPACE_VERTICAL : 0); } -void RectangleText::AddLine(const string16& line) { - const int line_width = gfx::GetStringWidth(line, font_list_); +void RectangleText::AddLine(const base::string16& line) { + const float line_width = GetStringWidthF(line, font_list_); if (line_width <= available_pixel_width_) { AddToCurrentLineWithWidth(line, line_width); } else { @@ -952,7 +937,7 @@ void RectangleText::AddLine(const string16& line) { if (words.Init()) { while (words.Advance()) { const bool truncate = !current_line_.empty(); - const string16& word = words.GetString(); + const base::string16& word = words.GetString(); const int lines_added = AddWord(word); if (lines_added) { if (truncate) { @@ -975,13 +960,13 @@ void RectangleText::AddLine(const string16& line) { NewLine(); } -int RectangleText::WrapWord(const string16& word) { +int RectangleText::WrapWord(const base::string16& word) { // Word is so wide that it must be fragmented. - string16 text = word; + base::string16 text = word; int lines_added = 0; bool first_fragment = true; while (!insufficient_height_ && !text.empty()) { - string16 fragment = + base::string16 fragment = ElideText(text, font_list_, available_pixel_width_, TRUNCATE_AT_END); // At least one character has to be added at every line, even if the @@ -997,7 +982,7 @@ int RectangleText::WrapWord(const string16& word) { return lines_added; } -int RectangleText::AddWordOverflow(const string16& word) { +int RectangleText::AddWordOverflow(const base::string16& word) { int lines_added = 0; // Unless this is the very first word, put it on a new line. @@ -1015,7 +1000,7 @@ int RectangleText::AddWordOverflow(const string16& word) { } else { const ElideBehavior elide_behavior = (wrap_behavior_ == ELIDE_LONG_WORDS ? ELIDE_AT_END : TRUNCATE_AT_END); - const string16 elided_word = + const base::string16 elided_word = ElideText(word, font_list_, available_pixel_width_, elide_behavior); AddToCurrentLine(elided_word); insufficient_width_ = true; @@ -1024,11 +1009,11 @@ int RectangleText::AddWordOverflow(const string16& word) { return lines_added; } -int RectangleText::AddWord(const string16& word) { +int RectangleText::AddWord(const base::string16& word) { int lines_added = 0; - string16 trimmed; + base::string16 trimmed; TrimWhitespace(word, TRIM_TRAILING, &trimmed); - const int trimmed_width = gfx::GetStringWidth(trimmed, font_list_); + const float trimmed_width = GetStringWidthF(trimmed, font_list_); if (trimmed_width <= available_pixel_width_) { // Word can be made to fit, no need to fragment it. if ((current_width_ + trimmed_width > available_pixel_width_) && NewLine()) @@ -1042,12 +1027,12 @@ int RectangleText::AddWord(const string16& word) { return lines_added; } -void RectangleText::AddToCurrentLine(const string16& text) { - AddToCurrentLineWithWidth(text, gfx::GetStringWidth(text, font_list_)); +void RectangleText::AddToCurrentLine(const base::string16& text) { + AddToCurrentLineWithWidth(text, GetStringWidthF(text, font_list_)); } -void RectangleText::AddToCurrentLineWithWidth(const string16& text, - int text_width) { +void RectangleText::AddToCurrentLineWithWidth(const base::string16& text, + float text_width) { if (current_height_ >= available_pixel_height_) { insufficient_height_ = true; return; @@ -1072,20 +1057,21 @@ bool RectangleText::NewLine() { } // namespace -bool ElideRectangleString(const string16& input, size_t max_rows, - size_t max_cols, bool strict, string16* output) { +bool ElideRectangleString(const base::string16& input, size_t max_rows, + size_t max_cols, bool strict, + base::string16* output) { RectangleString rect(max_rows, max_cols, strict, output); rect.Init(); rect.AddString(input); return rect.Finalize(); } -int ElideRectangleText(const string16& input, - const gfx::FontList& font_list, - int available_pixel_width, +int ElideRectangleText(const base::string16& input, + const FontList& font_list, + float available_pixel_width, int available_pixel_height, WordWrapBehavior wrap_behavior, - std::vector<string16>* lines) { + std::vector<base::string16>* lines) { RectangleText rect(font_list, available_pixel_width, available_pixel_height, @@ -1096,30 +1082,19 @@ int ElideRectangleText(const string16& input, return rect.Finalize(); } -int ElideRectangleText(const string16& input, - const gfx::Font& font, - int available_pixel_width, - int available_pixel_height, - WordWrapBehavior wrap_behavior, - std::vector<string16>* lines) { - return ElideRectangleText(input, gfx::FontList(font), - available_pixel_width, available_pixel_height, - wrap_behavior, lines); -} - -string16 TruncateString(const string16& string, size_t length) { +base::string16 TruncateString(const base::string16& string, size_t length) { if (string.size() <= length) // String fits, return it. return string; if (length == 0) // No room for the elide string, return an empty string. - return string16(); + return base::string16(); size_t max = length - 1; // Added to the end of strings that are too big. - static const char16 kElideString[] = { 0x2026, 0 }; + static const base::char16 kElideString[] = { 0x2026, 0 }; if (max == 0) // Just enough room for the elide string. diff --git a/chromium/ui/gfx/text_elider.h b/chromium/ui/gfx/text_elider.h index 008a1cd1b5b..4eaca828c7d 100644 --- a/chromium/ui/gfx/text_elider.h +++ b/chromium/ui/gfx/text_elider.h @@ -26,8 +26,8 @@ namespace gfx { class Font; class FontList; -UI_EXPORT extern const char kEllipsis[]; -UI_EXPORT extern const char16 kEllipsisUTF16[]; +GFX_EXPORT extern const char kEllipsis[]; +GFX_EXPORT extern const base::char16 kEllipsisUTF16[]; // Elides a well-formed email address (e.g. username@domain.com) to fit into // |available_pixel_width| using the specified |font_list|. @@ -39,13 +39,9 @@ UI_EXPORT extern const char16 kEllipsisUTF16[]; // 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). -UI_EXPORT string16 ElideEmail(const string16& email, - const gfx::FontList& font_list, - int available_pixel_width); -// Obsolete version. Use the above version which takes gfx::FontList. -UI_EXPORT string16 ElideEmail(const string16& email, - const gfx::Font& font, - int available_pixel_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. @@ -61,15 +57,10 @@ UI_EXPORT string16 ElideEmail(const string16& email, // 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. -UI_EXPORT string16 ElideUrl(const GURL& url, - const gfx::FontList& font_list, - int available_pixel_width, - const std::string& languages); -// Obsolete version. Use the above version which takes gfx::FontList. -UI_EXPORT string16 ElideUrl(const GURL& url, - const gfx::Font& font, - int available_pixel_width, - const std::string& languages); +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. @@ -82,15 +73,15 @@ enum ElideBehavior { // Elides |text| to fit in |available_pixel_width| according to the specified // |elide_behavior|. -UI_EXPORT string16 ElideText(const string16& text, - const gfx::FontList& font_list, - int available_pixel_width, - ElideBehavior elide_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. -UI_EXPORT string16 ElideText(const string16& text, - const gfx::Font& font, - int available_pixel_width, - ElideBehavior elide_behavior); +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 @@ -98,20 +89,16 @@ UI_EXPORT string16 ElideText(const string16& text, // filename is forced to have LTR directionality, which means that in RTL UI // the elided filename is wrapped with LRE (Left-To-Right Embedding) mark and // PDF (Pop Directional Formatting) mark. -UI_EXPORT string16 ElideFilename(const base::FilePath& filename, - const gfx::FontList& font_list, - int available_pixel_width); -// Obsolete version. Use the above version which takes gfx::FontList. -UI_EXPORT string16 ElideFilename(const base::FilePath& filename, - const gfx::Font& font, - int available_pixel_width); +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 UI_EXPORT SortedDisplayURL { +class GFX_EXPORT SortedDisplayURL { public: SortedDisplayURL(const GURL& url, const std::string& languages); SortedDisplayURL(); @@ -123,20 +110,20 @@ class UI_EXPORT SortedDisplayURL { int Compare(const SortedDisplayURL& other, icu::Collator* collator) const; // Returns the display string for the URL. - const string16& display_url() const { return display_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. - string16 AfterHost() const; + base::string16 AfterHost() const; // Host name minus 'www.'. Used by Compare. - string16 sort_host_; + base::string16 sort_host_; // End of the prefix (spec and separator) in display_url_. size_t prefix_end_; - string16 display_url_; + base::string16 display_url_; DISALLOW_COPY_AND_ASSIGN(SortedDisplayURL); }; @@ -154,8 +141,8 @@ class UI_EXPORT SortedDisplayURL { // puts "Hell...Tom" in str and returns true. // TODO(tsepez): Doesn't handle UTF-16 surrogate pairs properly. // TODO(tsepez): Doesn't handle bidi properly. -UI_EXPORT bool ElideString(const string16& input, int max_len, - string16* output); +GFX_EXPORT bool ElideString(const base::string16& input, int max_len, + base::string16* output); // Reformat |input| into |output| so that it fits into a |max_rows| by // |max_cols| rectangle of characters. Input newlines are respected, but @@ -166,9 +153,11 @@ UI_EXPORT bool ElideString(const string16& input, int max_len, // intra-word (respecting UTF-16 surrogate pairs) as necssary. Truncation // (indicated by an added 3 dots) occurs if the result is still too long. // Returns true if the input had to be truncated (and not just reformatted). -UI_EXPORT bool ElideRectangleString(const string16& input, size_t max_rows, - size_t max_cols, bool strict, - string16* output); +GFX_EXPORT bool ElideRectangleString(const base::string16& input, + size_t max_rows, + size_t max_cols, + bool strict, + base::string16* output); // Specifies the word wrapping behavior of |ElideRectangleText()| when a word // would exceed the available width. @@ -206,26 +195,20 @@ enum ReformattingResultFlags { // param. Returns a combination of |ReformattingResultFlags| that indicate // whether the given rectangle had insufficient space to accommodate |texŧ|, // leading to elision or truncation (and not just reformatting). -UI_EXPORT int ElideRectangleText(const string16& text, - const gfx::FontList& font_list, - int available_pixel_width, - int available_pixel_height, - WordWrapBehavior wrap_behavior, - std::vector<string16>* lines); -// Obsolete version. Use the above version which takes gfx::FontList. -UI_EXPORT int ElideRectangleText(const string16& text, - const gfx::Font& font, - int available_pixel_width, - int available_pixel_height, - WordWrapBehavior wrap_behavior, - std::vector<string16>* lines); +GFX_EXPORT int ElideRectangleText(const base::string16& text, + const gfx::FontList& font_list, + float available_pixel_width, + int available_pixel_height, + WordWrapBehavior wrap_behavior, + std::vector<base::string16>* lines); // Truncates the string to length characters. This breaks the string at // the first word break before length, adding the horizontal ellipsis // character (unicode character 0x2026) to render ... // The supplied string is returned if the string has length characters or // less. -UI_EXPORT string16 TruncateString(const string16& string, size_t length); +GFX_EXPORT base::string16 TruncateString(const base::string16& string, + size_t length); } // namespace gfx diff --git a/chromium/ui/gfx/text_elider_unittest.cc b/chromium/ui/gfx/text_elider_unittest.cc index 2a90e5d73cb..5fa74cbd101 100644 --- a/chromium/ui/gfx/text_elider_unittest.cc +++ b/chromium/ui/gfx/text_elider_unittest.cc @@ -13,6 +13,8 @@ #include "base/strings/utf_string_conversions.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/font.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/text_utils.h" #include "url/gurl.h" namespace gfx { @@ -41,36 +43,22 @@ struct TestData { }; void RunUrlTest(Testcase* testcases, size_t num_testcases) { - static const gfx::Font font; + 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, - font.GetStringWidth(UTF8ToUTF16(testcases[i].output)), - std::string())); + ElideUrl(url, font_list, available_width, std::string())); } } -gfx::Font GetTestingFont() { - gfx::Font font; -#if defined(OS_MACOSX) - // Use a specific font for certain tests on Mac. - // 1) Different Mac machines might be configured with different default font. - // The number of extra pixels needed to make ElideEmail/TestFilenameEliding - // tests work might vary per the default font. - // 2) This specific font helps expose the line width exceeding problem as in - // ElideRectangleTextCheckLineWidth. - font = gfx::Font("LucidaGrande", 12); -#endif - return font; -} - } // namespace -// TODO(ios): Complex eliding is off by one for some of those tests on iOS. -// See crbug.com/154019 +// 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) #define MAYBE_ElideEmail DISABLED_ElideEmail #else @@ -121,22 +109,14 @@ TEST(TextEliderTest, MAYBE_ElideEmail) { {"mmmmm@llllllllll", "m" + kEllipsisStr + "@l" + kEllipsisStr}, }; - const gfx::Font font = GetTestingFont(); + const FontList font_list; for (size_t i = 0; i < arraysize(testcases); ++i) { const string16 expected_output = UTF8ToUTF16(testcases[i].output); - int available_width = font.GetStringWidth(expected_output); -#if defined(OS_MACOSX) - // Give two extra pixels to offset the ceiling width returned by - // GetStringWidth on Mac. This workaround will no longer be needed once - // the floating point width is adopted (http://crbug.com/288987). - // Note that we need one more pixel than TestFilenameEliding because - // multiple strings are elided and we need to offset more. - available_width += 2; -#endif EXPECT_EQ(expected_output, - ElideEmail(UTF8ToUTF16(testcases[i].input), - font, - available_width)); + ElideEmail( + UTF8ToUTF16(testcases[i].input), + font_list, + GetStringWidthF(expected_output, font_list))); } } @@ -153,14 +133,14 @@ TEST(TextEliderTest, ElideEmailMoreSpace) { "supermegalongusername@withasuperlonnnggggdomain.gouv.qc.ca", }; - const gfx::Font font; + const FontList font_list; for (size_t i = 0; i < arraysize(test_width_factors); ++i) { - const int test_width = test_width_factors[i] * - font.GetAverageCharacterWidth(); + const int test_width = + 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, test_width)); + EXPECT_EQ(test_email, ElideEmail(test_email, font_list, test_width)); } } } @@ -199,23 +179,26 @@ TEST(TextEliderTest, TestTrailingEllipsisSlashEllipsisHack) { const std::string kEllipsisStr(kEllipsis); // Very little space, would cause double ellipsis. - gfx::Font font; + FontList font_list; GURL url("http://battersbox.com/directory/foo/peter_paul_and_mary.html"); - int available_width = font.GetStringWidth( - UTF8ToUTF16("battersbox.com/" + kEllipsisStr + "/" + kEllipsisStr)); + 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(font.GetStringWidth(UTF8ToUTF16(kEllipsisStr + "/" + kEllipsisStr)), - font.GetStringWidth(UTF8ToUTF16("d" + kEllipsisStr))); + 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, available_width, std::string()); + 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, available_width, std::string())); + ElideUrl(url, font_list, available_width, std::string())); // More space available - elide directories, partially elide filename. Testcase testcases[] = { @@ -288,8 +271,8 @@ TEST(TextEliderTest, TestFileURLEliding) { RunUrlTest(testcases, arraysize(testcases)); } -// TODO(ios): Complex eliding is off by one for some of those tests on iOS. -// See crbug.com/154019 +// 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) #define MAYBE_TestFilenameEliding DISABLED_TestFilenameEliding #else @@ -334,28 +317,22 @@ TEST(TextEliderTest, MAYBE_TestFilenameEliding) { "file.name.re" + kEllipsisStr + "emelylongext"} }; - static const gfx::Font font = GetTestingFont(); + 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); expected = base::i18n::GetDisplayStringInLTRDirectionality(expected); - int available_width = font.GetStringWidth(UTF8ToUTF16(testcases[i].output)); -#if defined(OS_MACOSX) - // Give one extra pixel to offset the ceiling width returned by - // GetStringWidth on Mac. This workaround will no longer be needed once - // the floating point width is adopted (http://crbug.com/288987). - available_width += 1; -#endif - EXPECT_EQ(expected, ElideFilename(filepath, font, available_width)); + EXPECT_EQ(expected, ElideFilename(filepath, font_list, + GetStringWidthF(UTF8ToUTF16(testcases[i].output), font_list))); } } TEST(TextEliderTest, ElideTextTruncate) { - const gfx::Font font; - const int kTestWidth = font.GetStringWidth(ASCIIToUTF16("Test")); + const FontList font_list; + const float kTestWidth = GetStringWidthF(ASCIIToUTF16("Test"), font_list); struct TestData { const char* input; - int width; + float width; const char* output; } cases[] = { { "", 0, "" }, @@ -367,20 +344,21 @@ TEST(TextEliderTest, ElideTextTruncate) { }; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - string16 result = ElideText(UTF8ToUTF16(cases[i].input), font, + string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list, cases[i].width, TRUNCATE_AT_END); EXPECT_EQ(cases[i].output, UTF16ToUTF8(result)); } } TEST(TextEliderTest, ElideTextEllipsis) { - const gfx::Font font; - const int kTestWidth = font.GetStringWidth(ASCIIToUTF16("Test")); + const FontList font_list; + const float kTestWidth = GetStringWidthF(ASCIIToUTF16("Test"), font_list); const char* kEllipsis = "\xE2\x80\xA6"; - const int kEllipsisWidth = font.GetStringWidth(UTF8ToUTF16(kEllipsis)); + const float kEllipsisWidth = + GetStringWidthF(UTF8ToUTF16(kEllipsis), font_list); struct TestData { const char* input; - int width; + float width; const char* output; } cases[] = { { "", 0, "" }, @@ -392,7 +370,7 @@ TEST(TextEliderTest, ElideTextEllipsis) { }; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(cases); ++i) { - string16 result = ElideText(UTF8ToUTF16(cases[i].input), font, + string16 result = ElideText(UTF8ToUTF16(cases[i].input), font_list, cases[i].width, ELIDE_AT_END); EXPECT_EQ(cases[i].output, UTF16ToUTF8(result)); } @@ -418,27 +396,27 @@ static void CheckSurrogatePairs(const string16& text, } TEST(TextEliderTest, ElideTextSurrogatePairs) { - const gfx::Font font; + 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 = UTF8ToUTF16(kSurrogate + "ab" + kSurrogate + kSurrogate + "cd"); - const int kTestStringWidth = font.GetStringWidth(kTestString); + const float kTestStringWidth = GetStringWidthF(kTestString, font_list); const char16 kSurrogateFirstChar = kTestString[0]; const char16 kSurrogateSecondChar = kTestString[1]; string16 result; // Elide |kTextString| to all possible widths and check that no instance of // |kSurrogate| was split in two. - for (int width = 0; width <= kTestStringWidth; width++) { - result = ElideText(kTestString, font, width, TRUNCATE_AT_END); + for (float width = 0; width <= kTestStringWidth; width++) { + result = ElideText(kTestString, font_list, width, TRUNCATE_AT_END); CheckSurrogatePairs(result, kSurrogateFirstChar, kSurrogateSecondChar); - result = ElideText(kTestString, font, width, ELIDE_AT_END); + result = ElideText(kTestString, font_list, width, ELIDE_AT_END); CheckSurrogatePairs(result, kSurrogateFirstChar, kSurrogateSecondChar); - result = ElideText(kTestString, font, width, ELIDE_IN_MIDDLE); + result = ElideText(kTestString, font_list, width, ELIDE_IN_MIDDLE); CheckSurrogatePairs(result, kSurrogateFirstChar, kSurrogateSecondChar); } } @@ -467,17 +445,19 @@ TEST(TextEliderTest, ElideTextLongStrings) { {data_scheme + million_a, long_string_end}, }; - const gfx::Font font; - int ellipsis_width = font.GetStringWidth(kEllipsisStr); + const FontList font_list; + float ellipsis_width = GetStringWidthF(kEllipsisStr, font_list); for (size_t i = 0; i < arraysize(testcases_end); ++i) { // Compare sizes rather than actual contents because if the test fails, // output is rather long. EXPECT_EQ(testcases_end[i].output.size(), - ElideText(testcases_end[i].input, font, - font.GetStringWidth(testcases_end[i].output), - ELIDE_AT_END).size()); + ElideText( + testcases_end[i].input, + font_list, + GetStringWidthF(testcases_end[i].output, font_list), + ELIDE_AT_END).size()); EXPECT_EQ(kEllipsisStr, - ElideText(testcases_end[i].input, font, ellipsis_width, + ElideText(testcases_end[i].input, font_list, ellipsis_width, ELIDE_AT_END)); } @@ -498,11 +478,13 @@ TEST(TextEliderTest, ElideTextLongStrings) { // 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, - font.GetStringWidth(testcases_middle[i].output), - ELIDE_AT_END).size()); + ElideText( + testcases_middle[i].input, + font_list, + GetStringWidthF(testcases_middle[i].output, font_list), + ELIDE_AT_END).size()); EXPECT_EQ(kEllipsisStr, - ElideText(testcases_middle[i].input, font, ellipsis_width, + ElideText(testcases_middle[i].input, font_list, ellipsis_width, ELIDE_AT_END)); } } @@ -580,13 +562,13 @@ TEST(TextEliderTest, ElideString) { } TEST(TextEliderTest, ElideRectangleText) { - const gfx::Font font; - const int line_height = font.GetHeight(); - const int test_width = font.GetStringWidth(ASCIIToUTF16("Test")); + const FontList font_list; + const int line_height = font_list.GetHeight(); + const float test_width = GetStringWidthF(ASCIIToUTF16("Test"), font_list); struct TestData { const char* input; - int available_pixel_width; + float available_pixel_width; int available_pixel_height; bool truncated_y; const char* output; @@ -622,7 +604,7 @@ TEST(TextEliderTest, ElideRectangleText) { std::vector<string16> lines; EXPECT_EQ(cases[i].truncated_y ? INSUFFICIENT_SPACE_VERTICAL : 0, ElideRectangleText(UTF8ToUTF16(cases[i].input), - font, + font_list, cases[i].available_pixel_width, cases[i].available_pixel_height, TRUNCATE_LONG_WORDS, @@ -637,14 +619,14 @@ TEST(TextEliderTest, ElideRectangleText) { } TEST(TextEliderTest, ElideRectangleTextPunctuation) { - const gfx::Font font; - const int line_height = font.GetHeight(); - const int test_width = font.GetStringWidth(ASCIIToUTF16("Test")); - const int test_t_width = font.GetStringWidth(ASCIIToUTF16("Test T")); + const FontList font_list; + const int line_height = font_list.GetHeight(); + const float test_width = GetStringWidthF(ASCIIToUTF16("Test"), font_list); + const float test_t_width = GetStringWidthF(ASCIIToUTF16("Test T"), font_list); struct TestData { const char* input; - int available_pixel_width; + float available_pixel_width; int available_pixel_height; bool wrap_words; bool truncated_x; @@ -662,7 +644,7 @@ TEST(TextEliderTest, ElideRectangleTextPunctuation) { (cases[i].wrap_words ? WRAP_LONG_WORDS : TRUNCATE_LONG_WORDS); EXPECT_EQ(cases[i].truncated_x ? INSUFFICIENT_SPACE_HORIZONTAL : 0, ElideRectangleText(UTF8ToUTF16(cases[i].input), - font, + font_list, cases[i].available_pixel_width, cases[i].available_pixel_height, wrap_behavior, @@ -677,15 +659,15 @@ TEST(TextEliderTest, ElideRectangleTextPunctuation) { } TEST(TextEliderTest, ElideRectangleTextLongWords) { - const gfx::Font font; + const FontList font_list; const int kAvailableHeight = 1000; const string16 kElidedTesting = UTF8ToUTF16(std::string("Tes") + kEllipsis); - const int elided_width = font.GetStringWidth(kElidedTesting); - const int test_width = font.GetStringWidth(ASCIIToUTF16("Test")); + const float elided_width = GetStringWidthF(kElidedTesting, font_list); + const float test_width = GetStringWidthF(ASCIIToUTF16("Test"), font_list); struct TestData { const char* input; - int available_pixel_width; + float available_pixel_width; WordWrapBehavior wrap_behavior; bool truncated_x; const char* output; @@ -723,7 +705,7 @@ TEST(TextEliderTest, ElideRectangleTextLongWords) { std::vector<string16> lines; EXPECT_EQ(cases[i].truncated_x ? INSUFFICIENT_SPACE_HORIZONTAL : 0, ElideRectangleText(UTF8ToUTF16(cases[i].input), - font, + font_list, cases[i].available_pixel_width, kAvailableHeight, cases[i].wrap_behavior, @@ -735,35 +717,30 @@ TEST(TextEliderTest, ElideRectangleTextLongWords) { } } -// TODO(ios): Complex eliding is off by one for some of those tests on iOS. -// See crbug.com/154019 -#if defined(OS_IOS) -#define MAYBE_ElideRectangleTextCheckLineWidth \ - DISABLED_ElideRectangleTextCheckLineWidth -#else -#define MAYBE_ElideRectangleTextCheckLineWidth ElideRectangleTextCheckLineWidth -#endif - // This test is to make sure that the width of each wrapped line does not // exceed the available width. On some platform like Mac, this test used to // 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, MAYBE_ElideRectangleTextCheckLineWidth) { - gfx::Font font = GetTestingFont(); - const int kAvailableWidth = 235; +TEST(TextEliderTest, ElideRectangleTextCheckLineWidth) { + FontList font_list; +#if defined(OS_MACOSX) && !defined(OS_IOS) + // Use a specific font to expose the line width exceeding problem. + font_list = FontList(Font("LucidaGrande", 12)); +#endif + 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; EXPECT_EQ(0, ElideRectangleText(UTF8ToUTF16(text), - font, + font_list, kAvailableWidth, kAvailableHeight, WRAP_LONG_WORDS, &lines)); ASSERT_EQ(2u, lines.size()); - EXPECT_LE(font.GetStringWidth(lines[0]), kAvailableWidth); - EXPECT_LE(font.GetStringWidth(lines[1]), kAvailableWidth); + EXPECT_LE(GetStringWidthF(lines[0], font_list), kAvailableWidth); + EXPECT_LE(GetStringWidthF(lines[1], font_list), kAvailableWidth); } TEST(TextEliderTest, ElideRectangleString) { diff --git a/chromium/ui/gfx/text_utils.h b/chromium/ui/gfx/text_utils.h index bd94902fba6..088f97cea9e 100644 --- a/chromium/ui/gfx/text_utils.h +++ b/chromium/ui/gfx/text_utils.h @@ -17,15 +17,19 @@ class FontList; // |accelerated_char_pos| and |accelerated_char_span| will be set to the index // and span of the last accelerated character, respectively, or -1 and 0 if // there was none. -UI_EXPORT base::string16 RemoveAcceleratorChar(const base::string16& s, - base::char16 accelerator_char, - int* accelerated_char_pos, - int* accelerated_char_span); +GFX_EXPORT base::string16 RemoveAcceleratorChar(const base::string16& s, + base::char16 accelerator_char, + int* accelerated_char_pos, + int* accelerated_char_span); // Returns the number of horizontal pixels needed to display the specified // |text| with |font_list|. -UI_EXPORT int GetStringWidth(const base::string16& text, - const FontList& font_list); +GFX_EXPORT int GetStringWidth(const base::string16& text, + const FontList& font_list); + +// This is same as GetStringWidth except that fractional width is returned. +GFX_EXPORT float GetStringWidthF(const base::string16& text, + const FontList& font_list); } // namespace gfx diff --git a/chromium/ui/gfx/text_utils_android.cc b/chromium/ui/gfx/text_utils_android.cc index c564b9b1db0..93938d57ff0 100644 --- a/chromium/ui/gfx/text_utils_android.cc +++ b/chromium/ui/gfx/text_utils_android.cc @@ -13,4 +13,9 @@ int GetStringWidth(const base::string16& text, const FontList& font_list) { return 0; } +float GetStringWidthF(const base::string16& text, const FontList& font_list) { + NOTIMPLEMENTED(); + return 0; +} + } // namespace gfx diff --git a/chromium/ui/gfx/text_utils_ios.mm b/chromium/ui/gfx/text_utils_ios.mm index 1841864ff85..56c01df7f55 100644 --- a/chromium/ui/gfx/text_utils_ios.mm +++ b/chromium/ui/gfx/text_utils_ios.mm @@ -14,9 +14,13 @@ namespace gfx { int GetStringWidth(const base::string16& text, const FontList& font_list) { + return std::ceil(GetStringWidthF(text, font_list)); +} + +float GetStringWidthF(const base::string16& text, const FontList& font_list) { NSString* ns_text = base::SysUTF16ToNSString(text); NativeFont native_font = font_list.GetPrimaryFont().GetNativeFont(); - return std::ceil([ns_text sizeWithFont:native_font].width); + return [ns_text sizeWithFont:native_font].width; } } // namespace gfx diff --git a/chromium/ui/gfx/text_utils_skia.cc b/chromium/ui/gfx/text_utils_skia.cc index 0de1156a14b..4ef0c234897 100644 --- a/chromium/ui/gfx/text_utils_skia.cc +++ b/chromium/ui/gfx/text_utils_skia.cc @@ -12,4 +12,8 @@ int GetStringWidth(const base::string16& text, const FontList& font_list) { return Canvas::GetStringWidth(text, font_list); } +float GetStringWidthF(const base::string16& text, const FontList& font_list) { + return Canvas::GetStringWidthF(text, font_list); +} + } // namespace gfx diff --git a/chromium/ui/gfx/transform.cc b/chromium/ui/gfx/transform.cc index 5f8a36760d1..7fe5174e750 100644 --- a/chromium/ui/gfx/transform.cc +++ b/chromium/ui/gfx/transform.cc @@ -11,6 +11,7 @@ #include "base/logging.h" #include "base/strings/stringprintf.h" +#include "ui/gfx/box_f.h" #include "ui/gfx/point.h" #include "ui/gfx/point3_f.h" #include "ui/gfx/rect.h" @@ -24,11 +25,19 @@ namespace gfx { namespace { // Taken from SkMatrix44. -const SkMScalar kEpsilon = 1e-8; +const SkMScalar kEpsilon = 1e-8f; SkMScalar TanDegrees(double degrees) { - SkMScalar radians = degrees * M_PI / 180; - return std::tan(radians); + double radians = degrees * M_PI / 180; + return SkDoubleToMScalar(std::tan(radians)); +} + +inline bool ApproximatelyZero(SkMScalar x, SkMScalar tolerance) { + return std::abs(x) <= tolerance; +} + +inline bool ApproximatelyOne(SkMScalar x, SkMScalar tolerance) { + return std::abs(x - SkDoubleToMScalar(1.0)) <= tolerance; } } // namespace @@ -169,7 +178,7 @@ void Transform::Translate3d(SkMScalar x, SkMScalar y, SkMScalar z) { matrix_.preTranslate(x, y, z); } -void Transform::SkewX(SkMScalar angle_x) { +void Transform::SkewX(double angle_x) { if (matrix_.isIdentity()) matrix_.set(0, 1, TanDegrees(angle_x)); else { @@ -179,7 +188,7 @@ void Transform::SkewX(SkMScalar angle_x) { } } -void Transform::SkewY(SkMScalar angle_y) { +void Transform::SkewY(double angle_y) { if (matrix_.isIdentity()) matrix_.set(1, 0, TanDegrees(angle_y)); else { @@ -209,6 +218,25 @@ void Transform::ConcatTransform(const Transform& transform) { matrix_.postConcat(transform.matrix_); } +bool Transform::IsApproximatelyIdentityOrTranslation( + SkMScalar tolerance) const { + DCHECK_GE(tolerance, 0); + return + ApproximatelyOne(matrix_.get(0, 0), tolerance) && + ApproximatelyZero(matrix_.get(1, 0), tolerance) && + ApproximatelyZero(matrix_.get(2, 0), tolerance) && + matrix_.get(3, 0) == 0 && + ApproximatelyZero(matrix_.get(0, 1), tolerance) && + ApproximatelyOne(matrix_.get(1, 1), tolerance) && + ApproximatelyZero(matrix_.get(2, 1), tolerance) && + matrix_.get(3, 1) == 0 && + ApproximatelyZero(matrix_.get(0, 2), tolerance) && + ApproximatelyZero(matrix_.get(1, 2), tolerance) && + ApproximatelyOne(matrix_.get(2, 2), tolerance) && + matrix_.get(3, 2) == 0 && + matrix_.get(3, 3) == 1; +} + bool Transform::IsIdentityOrIntegerTranslation() const { if (!IsIdentityOrTranslation()) return false; @@ -424,7 +452,34 @@ bool Transform::TransformRectReverse(RectF* rect) const { return true; } -bool Transform::Blend(const Transform& from, SkMScalar progress) { +void Transform::TransformBox(BoxF* box) const { + BoxF bounds; + bool first_point = true; + for (int corner = 0; corner < 8; ++corner) { + gfx::Point3F point = box->origin(); + point += gfx::Vector3dF(corner & 1 ? box->width() : 0.f, + corner & 2 ? box->height() : 0.f, + corner & 4 ? box->depth() : 0.f); + TransformPoint(&point); + if (first_point) { + bounds.set_origin(point); + first_point = false; + } else { + bounds.ExpandTo(point); + } + } + *box = bounds; +} + +bool Transform::TransformBoxReverse(BoxF* box) const { + gfx::Transform inverse = *this; + if (!GetInverse(&inverse)) + return false; + inverse.TransformBox(box); + return true; +} + +bool Transform::Blend(const Transform& from, double progress) { DecomposedTransform to_decomp; DecomposedTransform from_decomp; if (!DecomposeTransform(&to_decomp, *this) || @@ -448,8 +503,9 @@ void Transform::TransformPointInternal(const SkMatrix44& xform, xform.mapMScalars(p); - if (p[3] != 1 && abs(p[3]) > 0) { - point->SetPoint(p[0] / p[3], p[1] / p[3], p[2]/ p[3]); + if (p[3] != SK_MScalar1 && p[3] != 0.f) { + float w_inverse = SK_MScalar1 / p[3]; + point->SetPoint(p[0] * w_inverse, p[1] * w_inverse, p[2] * w_inverse); } else { point->SetPoint(p[0], p[1], p[2]); } diff --git a/chromium/ui/gfx/transform.h b/chromium/ui/gfx/transform.h index 8e51d7941be..5e3b8303340 100644 --- a/chromium/ui/gfx/transform.h +++ b/chromium/ui/gfx/transform.h @@ -14,6 +14,7 @@ namespace gfx { +class BoxF; class RectF; class Point; class Point3F; @@ -21,7 +22,7 @@ class Vector3dF; // 4x4 transformation matrix. Transform is cheap and explicitly allows // copy/assign. -class UI_EXPORT Transform { +class GFX_EXPORT Transform { public: enum SkipInitialization { @@ -96,8 +97,8 @@ class UI_EXPORT Transform { // Applies the current transformation on a skew and assigns the result // to |this|. - void SkewX(SkMScalar angle_x); - void SkewY(SkMScalar angle_y); + void SkewX(double angle_x); + void SkewY(double angle_y); // Applies the current transformation on a perspective transform and assigns // the result to |this|. @@ -119,6 +120,10 @@ class UI_EXPORT Transform { return !(matrix_.getType() & ~SkMatrix44::kTranslate_Mask); } + // Returns true if the matrix is either identity or pure translation, + // allowing for an amount of inaccuracy as specified by the parameter. + bool IsApproximatelyIdentityOrTranslation(SkMScalar tolerance) const; + // Returns true if the matrix is either a positive scale and/or a translation. bool IsPositiveScaleOrTranslation() const { if (!IsScaleOrTranslation()) @@ -179,12 +184,10 @@ class UI_EXPORT Transform { // Returns the x and y translation components of the matrix. Vector2dF To2dTranslation() const; - // Applies the transformation on the point. Returns true if the point is - // transformed successfully. + // Applies the transformation to the point. void TransformPoint(Point3F* point) const; - // Applies the transformation on the point. Returns true if the point is - // transformed successfully. Rounds the result to the nearest point. + // Applies the transformation to the point. void TransformPoint(Point* point) const; // Applies the reverse transformation on the point. Returns true if the @@ -195,17 +198,28 @@ class UI_EXPORT Transform { // transformation can be inverted. Rounds the result to the nearest point. bool TransformPointReverse(Point* point) const; - // Applies transformation on the rectangle. Returns true if the transformed - // rectangle was axis aligned. If it returns false, rect will be the - // smallest axis aligned bounding box containing the transformed rect. + // Applies transformation on the given rect. After the function completes, + // |rect| will be the smallest axis aligned bounding rect containing the + // transformed rect. void TransformRect(RectF* rect) const; - // Applies the reverse transformation on the rectangle. Returns true if - // the transformed rectangle was axis aligned. If it returns false, - // rect will be the smallest axis aligned bounding box containing the - // transformed rect. + // Applies the reverse transformation on the given rect. After the function + // completes, |rect| will be the smallest axis aligned bounding rect + // containing the transformed rect. Returns false if the matrix cannot be + // inverted. bool TransformRectReverse(RectF* rect) const; + // Applies transformation on the given box. After the function completes, + // |box| will be the smallest axis aligned bounding box containing the + // transformed box. + void TransformBox(BoxF* box) const; + + // Applies the reverse transformation on the given box. After the function + // completes, |box| will be the smallest axis aligned bounding box + // containing the transformed box. Returns false if the matrix cannot be + // inverted. + bool TransformBoxReverse(BoxF* box) const; + // Decomposes |this| and |from|, interpolates the decomposed values, and // sets |this| to the reconstituted result. Returns false if either matrix // can't be decomposed. Uses routines described in this spec: @@ -215,7 +229,7 @@ class UI_EXPORT Transform { // you're going to be calling this rapidly (e.g., in an animation) you should // decompose once using gfx::DecomposeTransforms and reuse your // DecomposedTransform. - bool Blend(const Transform& from, SkMScalar progress); + bool Blend(const Transform& from, double progress); // Returns |this| * |other|. Transform operator*(const Transform& other) const { diff --git a/chromium/ui/gfx/transform_unittest.cc b/chromium/ui/gfx/transform_unittest.cc index 4394af67896..0bf9dde73fc 100644 --- a/chromium/ui/gfx/transform_unittest.cc +++ b/chromium/ui/gfx/transform_unittest.cc @@ -14,6 +14,7 @@ #include "base/basictypes.h" #include "base/logging.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/box_f.h" #include "ui/gfx/point.h" #include "ui/gfx/point3_f.h" #include "ui/gfx/quad_f.h" @@ -90,22 +91,22 @@ bool MatricesAreNearlyEqual(const Transform& lhs, void InitializeTestMatrix(Transform* transform) { SkMatrix44& matrix = transform->matrix(); - matrix.setDouble(0, 0, 10.0); - matrix.setDouble(1, 0, 11.0); - matrix.setDouble(2, 0, 12.0); - matrix.setDouble(3, 0, 13.0); - matrix.setDouble(0, 1, 14.0); - matrix.setDouble(1, 1, 15.0); - matrix.setDouble(2, 1, 16.0); - matrix.setDouble(3, 1, 17.0); - matrix.setDouble(0, 2, 18.0); - matrix.setDouble(1, 2, 19.0); - matrix.setDouble(2, 2, 20.0); - matrix.setDouble(3, 2, 21.0); - matrix.setDouble(0, 3, 22.0); - matrix.setDouble(1, 3, 23.0); - matrix.setDouble(2, 3, 24.0); - matrix.setDouble(3, 3, 25.0); + matrix.set(0, 0, 10.f); + matrix.set(1, 0, 11.f); + matrix.set(2, 0, 12.f); + matrix.set(3, 0, 13.f); + matrix.set(0, 1, 14.f); + matrix.set(1, 1, 15.f); + matrix.set(2, 1, 16.f); + matrix.set(3, 1, 17.f); + matrix.set(0, 2, 18.f); + matrix.set(1, 2, 19.f); + matrix.set(2, 2, 20.f); + matrix.set(3, 2, 21.f); + matrix.set(0, 3, 22.f); + matrix.set(1, 3, 23.f); + matrix.set(2, 3, 24.f); + matrix.set(3, 3, 25.f); // Sanity check EXPECT_ROW1_EQ(10.0f, 14.0f, 18.0f, 22.0f, (*transform)); @@ -116,22 +117,22 @@ void InitializeTestMatrix(Transform* transform) { void InitializeTestMatrix2(Transform* transform) { SkMatrix44& matrix = transform->matrix(); - matrix.setDouble(0, 0, 30.0); - matrix.setDouble(1, 0, 31.0); - matrix.setDouble(2, 0, 32.0); - matrix.setDouble(3, 0, 33.0); - matrix.setDouble(0, 1, 34.0); - matrix.setDouble(1, 1, 35.0); - matrix.setDouble(2, 1, 36.0); - matrix.setDouble(3, 1, 37.0); - matrix.setDouble(0, 2, 38.0); - matrix.setDouble(1, 2, 39.0); - matrix.setDouble(2, 2, 40.0); - matrix.setDouble(3, 2, 41.0); - matrix.setDouble(0, 3, 42.0); - matrix.setDouble(1, 3, 43.0); - matrix.setDouble(2, 3, 44.0); - matrix.setDouble(3, 3, 45.0); + matrix.set(0, 0, 30.f); + matrix.set(1, 0, 31.f); + matrix.set(2, 0, 32.f); + matrix.set(3, 0, 33.f); + matrix.set(0, 1, 34.f); + matrix.set(1, 1, 35.f); + matrix.set(2, 1, 36.f); + matrix.set(3, 1, 37.f); + matrix.set(0, 2, 38.f); + matrix.set(1, 2, 39.f); + matrix.set(2, 2, 40.f); + matrix.set(3, 2, 41.f); + matrix.set(0, 3, 42.f); + matrix.set(1, 3, 43.f); + matrix.set(2, 3, 44.f); + matrix.set(3, 3, 45.f); // Sanity check EXPECT_ROW1_EQ(30.0f, 34.0f, 38.0f, 42.0f, (*transform)); @@ -140,6 +141,33 @@ void InitializeTestMatrix2(Transform* transform) { EXPECT_ROW4_EQ(33.0f, 37.0f, 41.0f, 45.0f, (*transform)); } +const SkMScalar kApproxZero = + SkFloatToMScalar(std::numeric_limits<float>::epsilon()); +const SkMScalar kApproxOne = 1 - kApproxZero; + +void InitializeApproxIdentityMatrix(Transform* transform) { + SkMatrix44& matrix = transform->matrix(); + matrix.set(0, 0, kApproxOne); + matrix.set(0, 1, kApproxZero); + matrix.set(0, 2, kApproxZero); + matrix.set(0, 3, kApproxZero); + + matrix.set(1, 0, kApproxZero); + matrix.set(1, 1, kApproxOne); + matrix.set(1, 2, kApproxZero); + matrix.set(1, 3, kApproxZero); + + matrix.set(2, 0, kApproxZero); + matrix.set(2, 1, kApproxZero); + matrix.set(2, 2, kApproxOne); + matrix.set(2, 3, kApproxZero); + + matrix.set(3, 0, kApproxZero); + matrix.set(3, 1, kApproxZero); + matrix.set(3, 2, kApproxZero); + matrix.set(3, 3, kApproxOne); +} + #ifdef SK_MSCALAR_IS_DOUBLE #define ERROR_THRESHOLD 1e-14 #else @@ -654,6 +682,23 @@ TEST(XFormTest, SetRotate2D) { } } +TEST(XFormTest, TransformPointWithExtremePerspective) { + Point3F point(1.f, 1.f, 1.f); + Transform perspective; + perspective.ApplyPerspectiveDepth(1.f); + Point3F transformed = point; + perspective.TransformPoint(&transformed); + EXPECT_EQ(point.ToString(), transformed.ToString()); + + transformed = point; + perspective.MakeIdentity(); + perspective.ApplyPerspectiveDepth(1.1f); + perspective.TransformPoint(&transformed); + EXPECT_FLOAT_EQ(11.f, transformed.x()); + EXPECT_FLOAT_EQ(11.f, transformed.y()); + EXPECT_FLOAT_EQ(11.f, transformed.z()); +} + TEST(XFormTest, BlendTranslate) { Transform from; for (int i = -5; i < 15; ++i) { @@ -738,14 +783,21 @@ TEST(XFormTest, CanBlend180DegreeRotation) { for (size_t index = 0; index < ARRAYSIZE_UNSAFE(axes); ++index) { for (int i = -5; i < 15; ++i) { Transform to; - to.RotateAbout(axes[index], 180); + to.RotateAbout(axes[index], 180.0); double t = i / 9.0; EXPECT_TRUE(to.Blend(from, t)); - Transform expected; - expected.RotateAbout(axes[index], 180 * t); + // A 180 degree rotation is exactly opposite on the sphere, therefore + // either great circle arc to it is equivalent (and numerical precision + // will determine which is closer). Test both directions. + Transform expected1; + expected1.RotateAbout(axes[index], 180.0 * t); + Transform expected2; + expected2.RotateAbout(axes[index], -180.0 * t); - EXPECT_TRUE(MatricesAreNearlyEqual(expected, to)); + EXPECT_TRUE(MatricesAreNearlyEqual(expected1, to) || + MatricesAreNearlyEqual(expected2, to)) + << "axis: " << index << ", i: " << i; } } } @@ -757,9 +809,9 @@ TEST(XFormTest, BlendScale) { to.Scale3d(5, 4, 3); double t = i / 9.0; EXPECT_TRUE(to.Blend(from, t)); - EXPECT_FLOAT_EQ(t * 4 + 1, to.matrix().get(0, 0)); - EXPECT_FLOAT_EQ(t * 3 + 1, to.matrix().get(1, 1)); - EXPECT_FLOAT_EQ(t * 2 + 1, to.matrix().get(2, 2)); + EXPECT_FLOAT_EQ(t * 4 + 1, to.matrix().get(0, 0)) << "i: " << i; + EXPECT_FLOAT_EQ(t * 3 + 1, to.matrix().get(1, 1)) << "i: " << i; + EXPECT_FLOAT_EQ(t * 2 + 1, to.matrix().get(2, 2)) << "i: " << i; } } @@ -767,12 +819,12 @@ TEST(XFormTest, BlendSkew) { Transform from; for (int i = 0; i < 2; ++i) { Transform to; - to.SkewX(20); - to.SkewY(10); + to.SkewX(10); + to.SkewY(5); double t = i; Transform expected; - expected.SkewX(t * 20); - expected.SkewY(t * 10); + expected.SkewX(t * 10); + expected.SkewY(t * 5); EXPECT_TRUE(to.Blend(from, t)); EXPECT_TRUE(MatricesAreNearlyEqual(expected, to)); } @@ -1201,7 +1253,7 @@ TEST(XFormTest, VerifyBlendForCompositeTransform) { // We short circuit if blend is >= 1, so to check the numerics, we will // check that we get close to what we expect when we're nearly done // interpolating. - to.Blend(from, .99999); + to.Blend(from, .99999f); // Recomposing the matrix results in a normalized matrix, so to verify we // need to normalize the expectedEndOfAnimation before comparing elements. @@ -1259,14 +1311,17 @@ TEST(XFormTest, FactorTRS) { EXPECT_TRUE(success); EXPECT_FLOAT_EQ(decomp.translate[0], degrees * 2); EXPECT_FLOAT_EQ(decomp.translate[1], -degrees * 3); - double rotation = std::acos(decomp.quaternion[3]) * 360.0 / M_PI; + double rotation = + std::acos(SkMScalarToDouble(decomp.quaternion[3])) * 360.0 / M_PI; while (rotation < 0.0) rotation += 360.0; while (rotation > 360.0) rotation -= 360.0; - EXPECT_FLOAT_EQ(rotation, degrees); - EXPECT_FLOAT_EQ(decomp.scale[0], degrees + 1); - EXPECT_FLOAT_EQ(decomp.scale[1], 2 * degrees + 1); + + const float epsilon = 0.00015f; + EXPECT_NEAR(rotation, degrees, epsilon); + EXPECT_NEAR(decomp.scale[0], degrees + 1, epsilon); + EXPECT_NEAR(decomp.scale[1], 2 * degrees + 1, epsilon); } } @@ -1282,15 +1337,15 @@ TEST(XFormTest, IntegerTranslation) { EXPECT_TRUE(transform.IsIdentityOrIntegerTranslation()); transform.MakeIdentity(); - transform.Translate3d(4.5, 0, 0); + transform.Translate3d(4.5f, 0, 0); EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation()); transform.MakeIdentity(); - transform.Translate3d(0, -6.7, 0); + transform.Translate3d(0, -6.7f, 0); EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation()); transform.MakeIdentity(); - transform.Translate3d(0, 0, 8.9); + transform.Translate3d(0, 0, 8.9f); EXPECT_FALSE(transform.IsIdentityOrIntegerTranslation()); } @@ -1329,10 +1384,10 @@ TEST(XFormTest, verifyMatrixInversion) { // Try to invert a matrix that is not invertible. // The inverse() function should reset the output matrix to identity. gfx::Transform uninvertible; - uninvertible.matrix().setDouble(0, 0, 0.0); - uninvertible.matrix().setDouble(1, 1, 0.0); - uninvertible.matrix().setDouble(2, 2, 0.0); - uninvertible.matrix().setDouble(3, 3, 0.0); + uninvertible.matrix().set(0, 0, 0.f); + uninvertible.matrix().set(1, 1, 0.f); + uninvertible.matrix().set(2, 2, 0.f); + uninvertible.matrix().set(3, 3, 0.f); EXPECT_FALSE(uninvertible.IsInvertible()); gfx::Transform inverse_of_uninvertible; @@ -1495,67 +1550,67 @@ TEST(XFormTest, verifyEqualsBooleanOperator) { // return false. Transform D; D = A; - D.matrix().setDouble(0, 0, 0.0); + D.matrix().set(0, 0, 0.f); EXPECT_FALSE(A == D); D = A; - D.matrix().setDouble(1, 0, 0.0); + D.matrix().set(1, 0, 0.f); EXPECT_FALSE(A == D); D = A; - D.matrix().setDouble(2, 0, 0.0); + D.matrix().set(2, 0, 0.f); EXPECT_FALSE(A == D); D = A; - D.matrix().setDouble(3, 0, 0.0); + D.matrix().set(3, 0, 0.f); EXPECT_FALSE(A == D); D = A; - D.matrix().setDouble(0, 1, 0.0); + D.matrix().set(0, 1, 0.f); EXPECT_FALSE(A == D); D = A; - D.matrix().setDouble(1, 1, 0.0); + D.matrix().set(1, 1, 0.f); EXPECT_FALSE(A == D); D = A; - D.matrix().setDouble(2, 1, 0.0); + D.matrix().set(2, 1, 0.f); EXPECT_FALSE(A == D); D = A; - D.matrix().setDouble(3, 1, 0.0); + D.matrix().set(3, 1, 0.f); EXPECT_FALSE(A == D); D = A; - D.matrix().setDouble(0, 2, 0.0); + D.matrix().set(0, 2, 0.f); EXPECT_FALSE(A == D); D = A; - D.matrix().setDouble(1, 2, 0.0); + D.matrix().set(1, 2, 0.f); EXPECT_FALSE(A == D); D = A; - D.matrix().setDouble(2, 2, 0.0); + D.matrix().set(2, 2, 0.f); EXPECT_FALSE(A == D); D = A; - D.matrix().setDouble(3, 2, 0.0); + D.matrix().set(3, 2, 0.f); EXPECT_FALSE(A == D); D = A; - D.matrix().setDouble(0, 3, 0.0); + D.matrix().set(0, 3, 0.f); EXPECT_FALSE(A == D); D = A; - D.matrix().setDouble(1, 3, 0.0); + D.matrix().set(1, 3, 0.f); EXPECT_FALSE(A == D); D = A; - D.matrix().setDouble(2, 3, 0.0); + D.matrix().set(2, 3, 0.f); EXPECT_FALSE(A == D); D = A; - D.matrix().setDouble(3, 3, 0.0); + D.matrix().set(3, 3, 0.f); EXPECT_FALSE(A == D); } @@ -1945,23 +2000,23 @@ TEST(XFormTest, verifyHasPerspective) { EXPECT_FALSE(A.HasPerspective()); A.MakeIdentity(); - A.matrix().setDouble(3, 0, -1.0); + A.matrix().set(3, 0, -1.f); EXPECT_TRUE(A.HasPerspective()); A.MakeIdentity(); - A.matrix().setDouble(3, 1, -1.0); + A.matrix().set(3, 1, -1.f); EXPECT_TRUE(A.HasPerspective()); A.MakeIdentity(); - A.matrix().setDouble(3, 2, -0.3); + A.matrix().set(3, 2, -0.3f); EXPECT_TRUE(A.HasPerspective()); A.MakeIdentity(); - A.matrix().setDouble(3, 3, 0.5); + A.matrix().set(3, 3, 0.5f); EXPECT_TRUE(A.HasPerspective()); A.MakeIdentity(); - A.matrix().setDouble(3, 3, 0.0); + A.matrix().set(3, 3, 0.f); EXPECT_TRUE(A.HasPerspective()); } @@ -2002,14 +2057,14 @@ TEST(XFormTest, verifyIsInvertible) { // to zero (i.e. camera positioned at the origin), is not invertible. A.MakeIdentity(); A.ApplyPerspectiveDepth(1.0); - A.matrix().setDouble(3, 3, 0.0); + A.matrix().set(3, 3, 0.f); EXPECT_FALSE(A.IsInvertible()); // Adding more to a non-invertible matrix will not make it invertible in the // general case. A.MakeIdentity(); A.ApplyPerspectiveDepth(1.0); - A.matrix().setDouble(3, 3, 0.0); + A.matrix().set(3, 3, 0.f); A.Scale3d(6.0, 7.0, 8.0); A.RotateAboutXAxis(10.0); A.RotateAboutYAxis(20.0); @@ -2019,10 +2074,10 @@ TEST(XFormTest, verifyIsInvertible) { // A degenerate matrix of all zeros is not invertible. A.MakeIdentity(); - A.matrix().setDouble(0, 0, 0.0); - A.matrix().setDouble(1, 1, 0.0); - A.matrix().setDouble(2, 2, 0.0); - A.matrix().setDouble(3, 3, 0.0); + A.matrix().set(0, 0, 0.f); + A.matrix().set(1, 1, 0.f); + A.matrix().set(2, 2, 0.f); + A.matrix().set(3, 3, 0.f); EXPECT_FALSE(A.IsInvertible()); } @@ -2038,67 +2093,67 @@ TEST(XFormTest, verifyIsIdentity) { // Modifying any one individual element should cause the matrix to no longer // be identity. A.MakeIdentity(); - A.matrix().setDouble(0, 0, 2.0); + A.matrix().set(0, 0, 2.f); EXPECT_FALSE(A.IsIdentity()); A.MakeIdentity(); - A.matrix().setDouble(1, 0, 2.0); + A.matrix().set(1, 0, 2.f); EXPECT_FALSE(A.IsIdentity()); A.MakeIdentity(); - A.matrix().setDouble(2, 0, 2.0); + A.matrix().set(2, 0, 2.f); EXPECT_FALSE(A.IsIdentity()); A.MakeIdentity(); - A.matrix().setDouble(3, 0, 2.0); + A.matrix().set(3, 0, 2.f); EXPECT_FALSE(A.IsIdentity()); A.MakeIdentity(); - A.matrix().setDouble(0, 1, 2.0); + A.matrix().set(0, 1, 2.f); EXPECT_FALSE(A.IsIdentity()); A.MakeIdentity(); - A.matrix().setDouble(1, 1, 2.0); + A.matrix().set(1, 1, 2.f); EXPECT_FALSE(A.IsIdentity()); A.MakeIdentity(); - A.matrix().setDouble(2, 1, 2.0); + A.matrix().set(2, 1, 2.f); EXPECT_FALSE(A.IsIdentity()); A.MakeIdentity(); - A.matrix().setDouble(3, 1, 2.0); + A.matrix().set(3, 1, 2.f); EXPECT_FALSE(A.IsIdentity()); A.MakeIdentity(); - A.matrix().setDouble(0, 2, 2.0); + A.matrix().set(0, 2, 2.f); EXPECT_FALSE(A.IsIdentity()); A.MakeIdentity(); - A.matrix().setDouble(1, 2, 2.0); + A.matrix().set(1, 2, 2.f); EXPECT_FALSE(A.IsIdentity()); A.MakeIdentity(); - A.matrix().setDouble(2, 2, 2.0); + A.matrix().set(2, 2, 2.f); EXPECT_FALSE(A.IsIdentity()); A.MakeIdentity(); - A.matrix().setDouble(3, 2, 2.0); + A.matrix().set(3, 2, 2.f); EXPECT_FALSE(A.IsIdentity()); A.MakeIdentity(); - A.matrix().setDouble(0, 3, 2.0); + A.matrix().set(0, 3, 2.f); EXPECT_FALSE(A.IsIdentity()); A.MakeIdentity(); - A.matrix().setDouble(1, 3, 2.0); + A.matrix().set(1, 3, 2.f); EXPECT_FALSE(A.IsIdentity()); A.MakeIdentity(); - A.matrix().setDouble(2, 3, 2.0); + A.matrix().set(2, 3, 2.f); EXPECT_FALSE(A.IsIdentity()); A.MakeIdentity(); - A.matrix().setDouble(3, 3, 2.0); + A.matrix().set(3, 3, 2.f); EXPECT_FALSE(A.IsIdentity()); } @@ -2116,73 +2171,123 @@ TEST(XFormTest, verifyIsIdentityOrTranslation) { // (2, 3) are the translation components, so modifying them should still // return true. A.MakeIdentity(); - A.matrix().setDouble(0, 0, 2.0); + A.matrix().set(0, 0, 2.f); EXPECT_FALSE(A.IsIdentityOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(1, 0, 2.0); + A.matrix().set(1, 0, 2.f); EXPECT_FALSE(A.IsIdentityOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(2, 0, 2.0); + A.matrix().set(2, 0, 2.f); EXPECT_FALSE(A.IsIdentityOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(3, 0, 2.0); + A.matrix().set(3, 0, 2.f); EXPECT_FALSE(A.IsIdentityOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(0, 1, 2.0); + A.matrix().set(0, 1, 2.f); EXPECT_FALSE(A.IsIdentityOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(1, 1, 2.0); + A.matrix().set(1, 1, 2.f); EXPECT_FALSE(A.IsIdentityOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(2, 1, 2.0); + A.matrix().set(2, 1, 2.f); EXPECT_FALSE(A.IsIdentityOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(3, 1, 2.0); + A.matrix().set(3, 1, 2.f); EXPECT_FALSE(A.IsIdentityOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(0, 2, 2.0); + A.matrix().set(0, 2, 2.f); EXPECT_FALSE(A.IsIdentityOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(1, 2, 2.0); + A.matrix().set(1, 2, 2.f); EXPECT_FALSE(A.IsIdentityOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(2, 2, 2.0); + A.matrix().set(2, 2, 2.f); EXPECT_FALSE(A.IsIdentityOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(3, 2, 2.0); + A.matrix().set(3, 2, 2.f); EXPECT_FALSE(A.IsIdentityOrTranslation()); // Note carefully - expecting true here. A.MakeIdentity(); - A.matrix().setDouble(0, 3, 2.0); + A.matrix().set(0, 3, 2.f); EXPECT_TRUE(A.IsIdentityOrTranslation()); // Note carefully - expecting true here. A.MakeIdentity(); - A.matrix().setDouble(1, 3, 2.0); + A.matrix().set(1, 3, 2.f); EXPECT_TRUE(A.IsIdentityOrTranslation()); // Note carefully - expecting true here. A.MakeIdentity(); - A.matrix().setDouble(2, 3, 2.0); + A.matrix().set(2, 3, 2.f); EXPECT_TRUE(A.IsIdentityOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(3, 3, 2.0); + A.matrix().set(3, 3, 2.f); EXPECT_FALSE(A.IsIdentityOrTranslation()); } +TEST(XFormTest, verifyIsApproximatelyIdentityOrTranslation) { + Transform A; + SkMatrix44& matrix = A.matrix(); + + // Exact pure translation. + A.MakeIdentity(); + + // Set translate values to values other than 0 or 1. + matrix.set(0, 3, 3.4f); + matrix.set(1, 3, 4.4f); + matrix.set(2, 3, 5.6f); + + EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(0)); + EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero)); + + // Approximately pure translation. + InitializeApproxIdentityMatrix(&A); + + // Some values must be exact. + matrix.set(3, 0, 0); + matrix.set(3, 1, 0); + matrix.set(3, 2, 0); + matrix.set(3, 3, 1); + + // Set translate values to values other than 0 or 1. + matrix.set(0, 3, 3.4f); + matrix.set(1, 3, 4.4f); + matrix.set(2, 3, 5.6f); + + EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0)); + EXPECT_TRUE(A.IsApproximatelyIdentityOrTranslation(kApproxZero)); + + // Not approximately pure translation. + InitializeApproxIdentityMatrix(&A); + + // Some values must be exact. + matrix.set(3, 0, 0); + matrix.set(3, 1, 0); + matrix.set(3, 2, 0); + matrix.set(3, 3, 1); + + // Set some values (not translate values) to values other than 0 or 1. + matrix.set(0, 1, 3.4f); + matrix.set(3, 2, 4.4f); + matrix.set(2, 0, 5.6f); + + EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(0)); + EXPECT_FALSE(A.IsApproximatelyIdentityOrTranslation(kApproxZero)); +} + TEST(XFormTest, verifyIsScaleOrTranslation) { Transform A; @@ -2199,72 +2304,72 @@ TEST(XFormTest, verifyIsScaleOrTranslation) { // Note carefully - expecting true here. A.MakeIdentity(); - A.matrix().setDouble(0, 0, 2.0); + A.matrix().set(0, 0, 2.f); EXPECT_TRUE(A.IsScaleOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(1, 0, 2.0); + A.matrix().set(1, 0, 2.f); EXPECT_FALSE(A.IsScaleOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(2, 0, 2.0); + A.matrix().set(2, 0, 2.f); EXPECT_FALSE(A.IsScaleOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(3, 0, 2.0); + A.matrix().set(3, 0, 2.f); EXPECT_FALSE(A.IsScaleOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(0, 1, 2.0); + A.matrix().set(0, 1, 2.f); EXPECT_FALSE(A.IsScaleOrTranslation()); // Note carefully - expecting true here. A.MakeIdentity(); - A.matrix().setDouble(1, 1, 2.0); + A.matrix().set(1, 1, 2.f); EXPECT_TRUE(A.IsScaleOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(2, 1, 2.0); + A.matrix().set(2, 1, 2.f); EXPECT_FALSE(A.IsScaleOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(3, 1, 2.0); + A.matrix().set(3, 1, 2.f); EXPECT_FALSE(A.IsScaleOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(0, 2, 2.0); + A.matrix().set(0, 2, 2.f); EXPECT_FALSE(A.IsScaleOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(1, 2, 2.0); + A.matrix().set(1, 2, 2.f); EXPECT_FALSE(A.IsScaleOrTranslation()); // Note carefully - expecting true here. A.MakeIdentity(); - A.matrix().setDouble(2, 2, 2.0); + A.matrix().set(2, 2, 2.f); EXPECT_TRUE(A.IsScaleOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(3, 2, 2.0); + A.matrix().set(3, 2, 2.f); EXPECT_FALSE(A.IsScaleOrTranslation()); // Note carefully - expecting true here. A.MakeIdentity(); - A.matrix().setDouble(0, 3, 2.0); + A.matrix().set(0, 3, 2.f); EXPECT_TRUE(A.IsScaleOrTranslation()); // Note carefully - expecting true here. A.MakeIdentity(); - A.matrix().setDouble(1, 3, 2.0); + A.matrix().set(1, 3, 2.f); EXPECT_TRUE(A.IsScaleOrTranslation()); // Note carefully - expecting true here. A.MakeIdentity(); - A.matrix().setDouble(2, 3, 2.0); + A.matrix().set(2, 3, 2.f); EXPECT_TRUE(A.IsScaleOrTranslation()); A.MakeIdentity(); - A.matrix().setDouble(3, 3, 2.0); + A.matrix().set(3, 3, 2.f); EXPECT_FALSE(A.IsScaleOrTranslation()); } @@ -2307,52 +2412,52 @@ static bool EmpiricallyPreserves2dAxisAlignment(const Transform& transform) { TEST(XFormTest, Preserves2dAxisAlignment) { static const struct TestCase { - double a; // row 1, column 1 - double b; // row 1, column 2 - double c; // row 2, column 1 - double d; // row 2, column 2 + SkMScalar a; // row 1, column 1 + SkMScalar b; // row 1, column 2 + SkMScalar c; // row 2, column 1 + SkMScalar d; // row 2, column 2 bool expected; } test_cases[] = { - { 3.0, 0.0, - 0.0, 4.0, true }, // basic case - { 0.0, 4.0, - 3.0, 0.0, true }, // rotate by 90 - { 0.0, 0.0, - 0.0, 4.0, true }, // degenerate x - { 3.0, 0.0, - 0.0, 0.0, true }, // degenerate y - { 0.0, 0.0, - 3.0, 0.0, true }, // degenerate x + rotate by 90 - { 0.0, 4.0, - 0.0, 0.0, true }, // degenerate y + rotate by 90 - { 3.0, 4.0, - 0.0, 0.0, false }, - { 0.0, 0.0, - 3.0, 4.0, false }, - { 0.0, 3.0, - 0.0, 4.0, false }, - { 3.0, 0.0, - 4.0, 0.0, false }, - { 3.0, 4.0, - 5.0, 0.0, false }, - { 3.0, 4.0, - 0.0, 5.0, false }, - { 3.0, 0.0, - 4.0, 5.0, false }, - { 0.0, 3.0, - 4.0, 5.0, false }, - { 2.0, 3.0, - 4.0, 5.0, false }, + { 3.f, 0.f, + 0.f, 4.f, true }, // basic case + { 0.f, 4.f, + 3.f, 0.f, true }, // rotate by 90 + { 0.f, 0.f, + 0.f, 4.f, true }, // degenerate x + { 3.f, 0.f, + 0.f, 0.f, true }, // degenerate y + { 0.f, 0.f, + 3.f, 0.f, true }, // degenerate x + rotate by 90 + { 0.f, 4.f, + 0.f, 0.f, true }, // degenerate y + rotate by 90 + { 3.f, 4.f, + 0.f, 0.f, false }, + { 0.f, 0.f, + 3.f, 4.f, false }, + { 0.f, 3.f, + 0.f, 4.f, false }, + { 3.f, 0.f, + 4.f, 0.f, false }, + { 3.f, 4.f, + 5.f, 0.f, false }, + { 3.f, 4.f, + 0.f, 5.f, false }, + { 3.f, 0.f, + 4.f, 5.f, false }, + { 0.f, 3.f, + 4.f, 5.f, false }, + { 2.f, 3.f, + 4.f, 5.f, false }, }; Transform transform; for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { const TestCase& value = test_cases[i]; transform.MakeIdentity(); - transform.matrix().setDouble(0, 0, value.a); - transform.matrix().setDouble(0, 1, value.b); - transform.matrix().setDouble(1, 0, value.c); - transform.matrix().setDouble(1, 1, value.d); + transform.matrix().set(0, 0, value.a); + transform.matrix().set(0, 1, value.b); + transform.matrix().set(1, 0, value.c); + transform.matrix().set(1, 1, value.d); if (value.expected) { EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); @@ -2368,19 +2473,19 @@ TEST(XFormTest, Preserves2dAxisAlignment) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { const TestCase& value = test_cases[i]; transform.MakeIdentity(); - transform.matrix().setDouble(0, 0, value.a); - transform.matrix().setDouble(0, 1, value.b); - transform.matrix().setDouble(1, 0, value.c); - transform.matrix().setDouble(1, 1, value.d); - - transform.matrix().setDouble(0, 2, 1.0); - transform.matrix().setDouble(0, 3, 2.0); - transform.matrix().setDouble(1, 2, 3.0); - transform.matrix().setDouble(1, 3, 4.0); - transform.matrix().setDouble(2, 0, 5.0); - transform.matrix().setDouble(2, 1, 6.0); - transform.matrix().setDouble(2, 2, 7.0); - transform.matrix().setDouble(2, 3, 8.0); + transform.matrix().set(0, 0, value.a); + transform.matrix().set(0, 1, value.b); + transform.matrix().set(1, 0, value.c); + transform.matrix().set(1, 1, value.d); + + transform.matrix().set(0, 2, 1.f); + transform.matrix().set(0, 3, 2.f); + transform.matrix().set(1, 2, 3.f); + transform.matrix().set(1, 3, 4.f); + transform.matrix().set(2, 0, 5.f); + transform.matrix().set(2, 1, 6.f); + transform.matrix().set(2, 2, 7.f); + transform.matrix().set(2, 3, 8.f); if (value.expected) { EXPECT_TRUE(EmpiricallyPreserves2dAxisAlignment(transform)); @@ -2396,23 +2501,23 @@ TEST(XFormTest, Preserves2dAxisAlignment) { for (size_t i = 0; i < ARRAYSIZE_UNSAFE(test_cases); ++i) { const TestCase& value = test_cases[i]; transform.MakeIdentity(); - transform.matrix().setDouble(0, 0, value.a); - transform.matrix().setDouble(0, 1, value.b); - transform.matrix().setDouble(1, 0, value.c); - transform.matrix().setDouble(1, 1, value.d); - - transform.matrix().setDouble(0, 2, 1.0); - transform.matrix().setDouble(0, 3, 2.0); - transform.matrix().setDouble(1, 2, 3.0); - transform.matrix().setDouble(1, 3, 4.0); - transform.matrix().setDouble(2, 0, 5.0); - transform.matrix().setDouble(2, 1, 6.0); - transform.matrix().setDouble(2, 2, 7.0); - transform.matrix().setDouble(2, 3, 8.0); - transform.matrix().setDouble(3, 0, 9.0); - transform.matrix().setDouble(3, 1, 10.0); - transform.matrix().setDouble(3, 2, 11.0); - transform.matrix().setDouble(3, 3, 12.0); + transform.matrix().set(0, 0, value.a); + transform.matrix().set(0, 1, value.b); + transform.matrix().set(1, 0, value.c); + transform.matrix().set(1, 1, value.d); + + transform.matrix().set(0, 2, 1.f); + transform.matrix().set(0, 3, 2.f); + transform.matrix().set(1, 2, 3.f); + transform.matrix().set(1, 3, 4.f); + transform.matrix().set(2, 0, 5.f); + transform.matrix().set(2, 1, 6.f); + transform.matrix().set(2, 2, 7.f); + transform.matrix().set(2, 3, 8.f); + transform.matrix().set(3, 0, 9.f); + transform.matrix().set(3, 1, 10.f); + transform.matrix().set(3, 2, 11.f); + transform.matrix().set(3, 3, 12.f); EXPECT_FALSE(EmpiricallyPreserves2dAxisAlignment(transform)); EXPECT_FALSE(transform.Preserves2dAxisAlignment()); @@ -2504,6 +2609,50 @@ TEST(XFormTest, To2dTranslation) { EXPECT_EQ(translation.ToString(), transform.To2dTranslation().ToString()); } +TEST(XFormTest, TransformRect) { + Transform translation; + translation.Translate(3.f, 7.f); + RectF rect(1.f, 2.f, 3.f, 4.f); + RectF expected(4.f, 9.f, 3.f, 4.f); + translation.TransformRect(&rect); + EXPECT_EQ(expected.ToString(), rect.ToString()); +} + +TEST(XFormTest, TransformRectReverse) { + Transform translation; + translation.Translate(3.f, 7.f); + RectF rect(1.f, 2.f, 3.f, 4.f); + RectF expected(-2.f, -5.f, 3.f, 4.f); + EXPECT_TRUE(translation.TransformRectReverse(&rect)); + EXPECT_EQ(expected.ToString(), rect.ToString()); + + Transform singular; + singular.Scale3d(0.f, 0.f, 0.f); + EXPECT_FALSE(singular.TransformRectReverse(&rect)); +} + +TEST(XFormTest, TransformBox) { + Transform translation; + translation.Translate3d(3.f, 7.f, 6.f); + BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f); + BoxF expected(4.f, 9.f, 9.f, 4.f, 5.f, 6.f); + translation.TransformBox(&box); + EXPECT_EQ(expected.ToString(), box.ToString()); +} + +TEST(XFormTest, TransformBoxReverse) { + Transform translation; + translation.Translate3d(3.f, 7.f, 6.f); + BoxF box(1.f, 2.f, 3.f, 4.f, 5.f, 6.f); + BoxF expected(-2.f, -5.f, -3.f, 4.f, 5.f, 6.f); + EXPECT_TRUE(translation.TransformBoxReverse(&box)); + EXPECT_EQ(expected.ToString(), box.ToString()); + + Transform singular; + singular.Scale3d(0.f, 0.f, 0.f); + EXPECT_FALSE(singular.TransformBoxReverse(&box)); +} + } // namespace } // namespace gfx diff --git a/chromium/ui/gfx/transform_util.cc b/chromium/ui/gfx/transform_util.cc index 9bb3bbcbcfb..655ce57f2bb 100644 --- a/chromium/ui/gfx/transform_util.cc +++ b/chromium/ui/gfx/transform_util.cc @@ -7,14 +7,21 @@ #include <algorithm> #include <cmath> +#include "base/logging.h" +#include "base/strings/stringprintf.h" #include "ui/gfx/point.h" +#include "ui/gfx/point3_f.h" +#include "ui/gfx/rect.h" namespace gfx { namespace { SkMScalar Length3(SkMScalar v[3]) { - return std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + double vd[3] = {SkMScalarToDouble(v[0]), SkMScalarToDouble(v[1]), + SkMScalarToDouble(v[2])}; + return SkDoubleToMScalar( + std::sqrt(vd[0] * vd[0] + vd[1] * vd[1] + vd[2] * vd[2])); } void Scale3(SkMScalar v[3], SkMScalar scale) { @@ -24,20 +31,20 @@ void Scale3(SkMScalar v[3], SkMScalar scale) { template <int n> SkMScalar Dot(const SkMScalar* a, const SkMScalar* b) { - SkMScalar toReturn = 0; + double total = 0.0; for (int i = 0; i < n; ++i) - toReturn += a[i] * b[i]; - return toReturn; + total += a[i] * b[i]; + return SkDoubleToMScalar(total); } template <int n> void Combine(SkMScalar* out, const SkMScalar* a, const SkMScalar* b, - SkMScalar scale_a, - SkMScalar scale_b) { + double scale_a, + double scale_b) { for (int i = 0; i < n; ++i) - out[i] = a[i] * scale_a + b[i] * scale_b; + out[i] = SkDoubleToMScalar(a[i] * scale_a + b[i] * scale_b); } void Cross3(SkMScalar out[3], SkMScalar a[3], SkMScalar b[3]) { @@ -49,15 +56,19 @@ void Cross3(SkMScalar out[3], SkMScalar a[3], SkMScalar b[3]) { out[2] = z; } +SkMScalar Round(SkMScalar n) { + return SkDoubleToMScalar(std::floor(SkMScalarToDouble(n) + 0.5)); +} + // Taken from http://www.w3.org/TR/css3-transforms/. bool Slerp(SkMScalar out[4], const SkMScalar q1[4], const SkMScalar q2[4], - SkMScalar progress) { - SkMScalar product = Dot<4>(q1, q2); + double progress) { + double product = Dot<4>(q1, q2); // Clamp product to -1.0 <= product <= 1.0. - product = std::min(std::max(product, -SK_MScalar1), SK_MScalar1); + product = std::min(std::max(product, -1.0), 1.0); // Interpolate angles along the shortest path. For example, to interpolate // between a 175 degree angle and a 185 degree angle, interpolate along the @@ -66,25 +77,25 @@ bool Slerp(SkMScalar out[4], // the current W3C spec. Fixing the spec to match this approach is discussed // at: // http://lists.w3.org/Archives/Public/www-style/2013May/0131.html - SkMScalar scale1 = SK_MScalar1; + double scale1 = 1.0; if (product < 0) { product = -product; - scale1 = -SK_MScalar1; + scale1 = -1.0; } - const SkMScalar epsilon = 1e-5; - if (std::abs(product - SK_MScalar1) < epsilon) { + const double epsilon = 1e-5; + if (std::abs(product - 1.0) < epsilon) { for (int i = 0; i < 4; ++i) out[i] = q1[i]; return true; } - SkMScalar denom = std::sqrt(1 - product * product); - SkMScalar theta = std::acos(product); - SkMScalar w = std::sin(progress * theta) * (1 / denom); + double denom = std::sqrt(1.0 - product * product); + double theta = std::acos(product); + double w = std::sin(progress * theta) * (1.0 / denom); scale1 *= std::cos(progress * theta) - product * w; - SkMScalar scale2 = w; + double scale2 = w; Combine<4>(out, q1, q2, scale1, scale2); return true; @@ -104,6 +115,163 @@ bool Normalize(SkMatrix44& m) { return true; } +SkMatrix44 BuildPerspectiveMatrix(const DecomposedTransform& decomp) { + SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor); + + for (int i = 0; i < 4; i++) + matrix.setDouble(3, i, decomp.perspective[i]); + return matrix; +} + +SkMatrix44 BuildTranslationMatrix(const DecomposedTransform& decomp) { + SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor); + // Implicitly calls matrix.setIdentity() + matrix.setTranslate(SkDoubleToMScalar(decomp.translate[0]), + SkDoubleToMScalar(decomp.translate[1]), + SkDoubleToMScalar(decomp.translate[2])); + return matrix; +} + +SkMatrix44 BuildSnappedTranslationMatrix(DecomposedTransform decomp) { + decomp.translate[0] = Round(decomp.translate[0]); + decomp.translate[1] = Round(decomp.translate[1]); + decomp.translate[2] = Round(decomp.translate[2]); + return BuildTranslationMatrix(decomp); +} + +SkMatrix44 BuildRotationMatrix(const DecomposedTransform& decomp) { + double x = decomp.quaternion[0]; + double y = decomp.quaternion[1]; + double z = decomp.quaternion[2]; + double w = decomp.quaternion[3]; + + SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor); + + // Implicitly calls matrix.setIdentity() + matrix.set3x3(1.0 - 2.0 * (y * y + z * z), + 2.0 * (x * y + z * w), + 2.0 * (x * z - y * w), + 2.0 * (x * y - z * w), + 1.0 - 2.0 * (x * x + z * z), + 2.0 * (y * z + x * w), + 2.0 * (x * z + y * w), + 2.0 * (y * z - x * w), + 1.0 - 2.0 * (x * x + y * y)); + return matrix; +} + +SkMatrix44 BuildSnappedRotationMatrix(const DecomposedTransform& decomp) { + // Create snapped rotation. + SkMatrix44 rotation_matrix = BuildRotationMatrix(decomp); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + SkMScalar value = rotation_matrix.get(i, j); + // Snap values to -1, 0 or 1. + if (value < -0.5f) { + value = -1.0f; + } else if (value > 0.5f) { + value = 1.0f; + } else { + value = 0.0f; + } + rotation_matrix.set(i, j, value); + } + } + return rotation_matrix; +} + +SkMatrix44 BuildSkewMatrix(const DecomposedTransform& decomp) { + SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor); + + SkMatrix44 temp(SkMatrix44::kIdentity_Constructor); + if (decomp.skew[2]) { + temp.setDouble(1, 2, decomp.skew[2]); + matrix.preConcat(temp); + } + + if (decomp.skew[1]) { + temp.setDouble(1, 2, 0); + temp.setDouble(0, 2, decomp.skew[1]); + matrix.preConcat(temp); + } + + if (decomp.skew[0]) { + temp.setDouble(0, 2, 0); + temp.setDouble(0, 1, decomp.skew[0]); + matrix.preConcat(temp); + } + return matrix; +} + +SkMatrix44 BuildScaleMatrix(const DecomposedTransform& decomp) { + SkMatrix44 matrix(SkMatrix44::kUninitialized_Constructor); + matrix.setScale(SkDoubleToMScalar(decomp.scale[0]), + SkDoubleToMScalar(decomp.scale[1]), + SkDoubleToMScalar(decomp.scale[2])); + return matrix; +} + +SkMatrix44 BuildSnappedScaleMatrix(DecomposedTransform decomp) { + decomp.scale[0] = Round(decomp.scale[0]); + decomp.scale[1] = Round(decomp.scale[1]); + decomp.scale[2] = Round(decomp.scale[2]); + return BuildScaleMatrix(decomp); +} + +Transform ComposeTransform(const SkMatrix44& perspective, + const SkMatrix44& translation, + const SkMatrix44& rotation, + const SkMatrix44& skew, + const SkMatrix44& scale) { + SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor); + + matrix.preConcat(perspective); + matrix.preConcat(translation); + matrix.preConcat(rotation); + matrix.preConcat(skew); + matrix.preConcat(scale); + + Transform to_return; + to_return.matrix() = matrix; + return to_return; +} + +bool CheckViewportPointMapsWithinOnePixel(const Point& point, + const Transform& transform) { + Point3F point_original(point); + Point3F point_transformed(point); + + // Can't use TransformRect here since it would give us the axis-aligned + // bounding rect of the 4 points in the initial rectable which is not what we + // want. + transform.TransformPoint(&point_transformed); + + if ((point_transformed - point_original).Length() > 1.f) { + // The changed distance should not be more than 1 pixel. + return false; + } + return true; +} + +bool CheckTransformsMapsIntViewportWithinOnePixel(const Rect& viewport, + const Transform& original, + const Transform& snapped) { + + Transform original_inv(Transform::kSkipInitialization); + bool invertible = true; + invertible &= original.GetInverse(&original_inv); + DCHECK(invertible) << "Non-invertible transform, cannot snap."; + + Transform combined = snapped * original_inv; + + return CheckViewportPointMapsWithinOnePixel(viewport.origin(), combined) && + CheckViewportPointMapsWithinOnePixel(viewport.top_right(), combined) && + CheckViewportPointMapsWithinOnePixel(viewport.bottom_left(), + combined) && + CheckViewportPointMapsWithinOnePixel(viewport.bottom_right(), + combined); +} + } // namespace Transform GetScaleTransform(const Point& anchor, float scale) { @@ -126,9 +294,9 @@ DecomposedTransform::DecomposedTransform() { bool BlendDecomposedTransforms(DecomposedTransform* out, const DecomposedTransform& to, const DecomposedTransform& from, - SkMScalar progress) { - SkMScalar scalea = progress; - SkMScalar scaleb = SK_MScalar1 - progress; + double progress) { + double scalea = progress; + double scaleb = 1.0 - progress; Combine<3>(out->translate, to.translate, from.translate, scalea, scaleb); Combine<3>(out->scale, to.scale, from.scale, scalea, scaleb); Combine<3>(out->skew, to.skew, from.skew, scalea, scaleb); @@ -266,54 +434,68 @@ bool DecomposeTransform(DecomposedTransform* decomp, // Taken from http://www.w3.org/TR/css3-transforms/. Transform ComposeTransform(const DecomposedTransform& decomp) { - SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor); - for (int i = 0; i < 4; i++) - matrix.set(3, i, decomp.perspective[i]); + SkMatrix44 perspective = BuildPerspectiveMatrix(decomp); + SkMatrix44 translation = BuildTranslationMatrix(decomp); + SkMatrix44 rotation = BuildRotationMatrix(decomp); + SkMatrix44 skew = BuildSkewMatrix(decomp); + SkMatrix44 scale = BuildScaleMatrix(decomp); - matrix.preTranslate( - decomp.translate[0], decomp.translate[1], decomp.translate[2]); + return ComposeTransform(perspective, translation, rotation, skew, scale); +} - SkMScalar x = decomp.quaternion[0]; - SkMScalar y = decomp.quaternion[1]; - SkMScalar z = decomp.quaternion[2]; - SkMScalar w = decomp.quaternion[3]; +bool SnapTransform(Transform* out, + const Transform& transform, + const Rect& viewport) { + DecomposedTransform decomp; + DecomposeTransform(&decomp, transform); - SkMatrix44 rotation_matrix(SkMatrix44::kUninitialized_Constructor); - rotation_matrix.set3x3(1.0 - 2.0 * (y * y + z * z), - 2.0 * (x * y + z * w), - 2.0 * (x * z - y * w), - 2.0 * (x * y - z * w), - 1.0 - 2.0 * (x * x + z * z), - 2.0 * (y * z + x * w), - 2.0 * (x * z + y * w), - 2.0 * (y * z - x * w), - 1.0 - 2.0 * (x * x + y * y)); + SkMatrix44 rotation_matrix = BuildSnappedRotationMatrix(decomp); + SkMatrix44 translation = BuildSnappedTranslationMatrix(decomp); + SkMatrix44 scale = BuildSnappedScaleMatrix(decomp); - matrix.preConcat(rotation_matrix); + // Rebuild matrices for other unchanged components. + SkMatrix44 perspective = BuildPerspectiveMatrix(decomp); - SkMatrix44 temp(SkMatrix44::kIdentity_Constructor); - if (decomp.skew[2]) { - temp.set(1, 2, decomp.skew[2]); - matrix.preConcat(temp); - } + // Completely ignore the skew. + SkMatrix44 skew(SkMatrix44::kIdentity_Constructor); - if (decomp.skew[1]) { - temp.set(1, 2, 0); - temp.set(0, 2, decomp.skew[1]); - matrix.preConcat(temp); - } + // Get full tranform + Transform snapped = + ComposeTransform(perspective, translation, rotation_matrix, skew, scale); - if (decomp.skew[0]) { - temp.set(0, 2, 0); - temp.set(0, 1, decomp.skew[0]); - matrix.preConcat(temp); + // Verify that viewport is not moved unnaturally. + bool snappable = + CheckTransformsMapsIntViewportWithinOnePixel(viewport, transform, snapped); + if (snappable) { + *out = snapped; } + return snappable; +} - matrix.preScale(decomp.scale[0], decomp.scale[1], decomp.scale[2]); - - Transform to_return; - to_return.matrix() = matrix; - return to_return; +std::string DecomposedTransform::ToString() const { + return base::StringPrintf( + "translate: %+0.4f %+0.4f %+0.4f\n" + "scale: %+0.4f %+0.4f %+0.4f\n" + "skew: %+0.4f %+0.4f %+0.4f\n" + "perspective: %+0.4f %+0.4f %+0.4f %+0.4f\n" + "quaternion: %+0.4f %+0.4f %+0.4f %+0.4f\n", + translate[0], + translate[1], + translate[2], + scale[0], + scale[1], + scale[2], + skew[0], + skew[1], + skew[2], + perspective[0], + perspective[1], + perspective[2], + perspective[3], + quaternion[0], + quaternion[1], + quaternion[2], + quaternion[3]); } } // namespace ui diff --git a/chromium/ui/gfx/transform_util.h b/chromium/ui/gfx/transform_util.h index be5ba4c03ce..a77ded28f73 100644 --- a/chromium/ui/gfx/transform_util.h +++ b/chromium/ui/gfx/transform_util.h @@ -11,13 +11,14 @@ namespace gfx { class Point; +class Rect; // Returns a scale transform at |anchor| point. -UI_EXPORT Transform GetScaleTransform(const Point& anchor, float scale); +GFX_EXPORT Transform GetScaleTransform(const Point& anchor, float scale); // Contains the components of a factored transform. These components may be // blended and recomposed. -struct UI_EXPORT DecomposedTransform { +struct GFX_EXPORT DecomposedTransform { // The default constructor initializes the components in such a way that // if used with Compose below, will produce the identity transform. DecomposedTransform(); @@ -28,6 +29,8 @@ struct UI_EXPORT DecomposedTransform { SkMScalar perspective[4]; SkMScalar quaternion[4]; + std::string ToString() const; + // Copy and assign are allowed. }; @@ -35,21 +38,25 @@ struct UI_EXPORT DecomposedTransform { // routines described in http://www.w3.org/TR/css3-3d-transform/. // |progress| is in the range [0, 1] (0 leaves |out| unchanged, and 1 // assigns |from| to |out|). -UI_EXPORT bool BlendDecomposedTransforms(DecomposedTransform* out, - const DecomposedTransform& to, - const DecomposedTransform& from, - SkMScalar progress); +GFX_EXPORT bool BlendDecomposedTransforms(DecomposedTransform* out, + const DecomposedTransform& to, + const DecomposedTransform& from, + double progress); // Decomposes this transform into its translation, scale, skew, perspective, // and rotation components following the routines detailed in this spec: // http://www.w3.org/TR/css3-3d-transforms/. -UI_EXPORT bool DecomposeTransform(DecomposedTransform* out, - const Transform& transform); +GFX_EXPORT bool DecomposeTransform(DecomposedTransform* out, + const Transform& transform); // Composes a transform from the given translation, scale, skew, prespective, // and rotation components following the routines detailed in this spec: // http://www.w3.org/TR/css3-3d-transforms/. -UI_EXPORT Transform ComposeTransform(const DecomposedTransform& decomp); +GFX_EXPORT Transform ComposeTransform(const DecomposedTransform& decomp); + +GFX_EXPORT bool SnapTransform(Transform* out, + const Transform& transform, + const Rect& viewport); } // namespace gfx diff --git a/chromium/ui/gfx/transform_util_unittest.cc b/chromium/ui/gfx/transform_util_unittest.cc index 94195c29bb9..41bfc40783a 100644 --- a/chromium/ui/gfx/transform_util_unittest.cc +++ b/chromium/ui/gfx/transform_util_unittest.cc @@ -6,6 +6,8 @@ #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/point.h" +#include "ui/gfx/point3_f.h" +#include "ui/gfx/rect.h" namespace gfx { namespace { @@ -30,5 +32,149 @@ TEST(TransformUtilTest, GetScaleTransform) { } } +TEST(TransformUtilTest, SnapRotation) { + Transform result(Transform::kSkipInitialization); + Transform transform; + transform.RotateAboutZAxis(89.99); + + Rect viewport(1920, 1200); + bool snapped = SnapTransform(&result, transform, viewport); + + EXPECT_TRUE(snapped) << "Viewport should snap for this rotation."; +} + +TEST(TransformUtilTest, SnapRotationDistantViewport) { + const int kOffset = 5000; + Transform result(Transform::kSkipInitialization); + Transform transform; + + transform.RotateAboutZAxis(89.99); + + Rect viewport(kOffset, kOffset, 1920, 1200); + bool snapped = SnapTransform(&result, transform, viewport); + + EXPECT_FALSE(snapped) << "Distant viewport shouldn't snap by more than 1px."; +} + +TEST(TransformUtilTest, NoSnapRotation) { + Transform result(Transform::kSkipInitialization); + Transform transform; + const int kOffset = 5000; + + transform.RotateAboutZAxis(89.9); + + Rect viewport(kOffset, kOffset, 1920, 1200); + bool snapped = SnapTransform(&result, transform, viewport); + + EXPECT_FALSE(snapped) << "Viewport should not snap for this rotation."; +} + +// Translations should always be snappable, the most we would move is 0.5 +// pixels towards either direction to the nearest value in each component. +TEST(TransformUtilTest, SnapTranslation) { + Transform result(Transform::kSkipInitialization); + Transform transform; + + transform.Translate3d( + SkDoubleToMScalar(1.01), SkDoubleToMScalar(1.99), SkDoubleToMScalar(3.0)); + + Rect viewport(1920, 1200); + bool snapped = SnapTransform(&result, transform, viewport); + + EXPECT_TRUE(snapped) << "Viewport should snap for this translation."; +} + +TEST(TransformUtilTest, SnapTranslationDistantViewport) { + Transform result(Transform::kSkipInitialization); + Transform transform; + const int kOffset = 5000; + + transform.Translate3d( + SkDoubleToMScalar(1.01), SkDoubleToMScalar(1.99), SkDoubleToMScalar(3.0)); + + Rect viewport(kOffset, kOffset, 1920, 1200); + bool snapped = SnapTransform(&result, transform, viewport); + + EXPECT_TRUE(snapped) + << "Distant viewport should still snap by less than 1px."; +} + +TEST(TransformUtilTest, SnapScale) { + Transform result(Transform::kSkipInitialization); + Transform transform; + + transform.Scale3d(SkDoubleToMScalar(5.0), + SkDoubleToMScalar(2.00001), + SkDoubleToMScalar(1.0)); + Rect viewport(1920, 1200); + bool snapped = SnapTransform(&result, transform, viewport); + + EXPECT_TRUE(snapped) << "Viewport should snap for this scaling."; +} + +TEST(TransformUtilTest, NoSnapScale) { + Transform result(Transform::kSkipInitialization); + Transform transform; + + transform.Scale3d( + SkDoubleToMScalar(5.0), SkDoubleToMScalar(2.1), SkDoubleToMScalar(1.0)); + Rect viewport(1920, 1200); + bool snapped = SnapTransform(&result, transform, viewport); + + EXPECT_FALSE(snapped) << "Viewport shouldn't snap for this scaling."; +} + +TEST(TransformUtilTest, SnapCompositeTransform) { + Transform result(Transform::kSkipInitialization); + Transform transform; + + transform.Translate3d(SkDoubleToMScalar(30.5), SkDoubleToMScalar(20.0), + SkDoubleToMScalar(10.1)); + transform.RotateAboutZAxis(89.99); + transform.Scale3d(SkDoubleToMScalar(1.0), + SkDoubleToMScalar(3.00001), + SkDoubleToMScalar(2.0)); + + Rect viewport(1920, 1200); + bool snapped = SnapTransform(&result, transform, viewport); + ASSERT_TRUE(snapped) << "Viewport should snap all components."; + + Point3F point; + + point = Point3F(viewport.origin()); + result.TransformPoint(&point); + EXPECT_EQ(Point3F(31.f, 20.f, 10.f), point) << "Transformed origin"; + + point = Point3F(viewport.top_right()); + result.TransformPoint(&point); + EXPECT_EQ(Point3F(31.f, 1940.f, 10.f), point) << "Transformed top-right"; + + point = Point3F(viewport.bottom_left()); + result.TransformPoint(&point); + EXPECT_EQ(Point3F(-3569.f, 20.f, 10.f), point) << "Transformed bottom-left"; + + point = Point3F(viewport.bottom_right()); + result.TransformPoint(&point); + EXPECT_EQ(Point3F(-3569.f, 1940.f, 10.f), point) + << "Transformed bottom-right"; +} + +TEST(TransformUtilTest, NoSnapSkewedCompositeTransform) { + Transform result(Transform::kSkipInitialization); + Transform transform; + + + transform.RotateAboutZAxis(89.99); + transform.Scale3d(SkDoubleToMScalar(1.0), + SkDoubleToMScalar(3.00001), + SkDoubleToMScalar(2.0)); + transform.Translate3d(SkDoubleToMScalar(30.5), SkDoubleToMScalar(20.0), + SkDoubleToMScalar(10.1)); + transform.SkewX(20.0); + Rect viewport(1920, 1200); + bool snapped = SnapTransform(&result, transform, viewport); + EXPECT_FALSE(snapped) << "Skewed viewport should not snap."; +} + } // namespace } // namespace gfx diff --git a/chromium/ui/gfx/ui_gfx_exports.cc b/chromium/ui/gfx/ui_gfx_exports.cc new file mode 100644 index 00000000000..ca95eb33194 --- /dev/null +++ b/chromium/ui/gfx/ui_gfx_exports.cc @@ -0,0 +1,10 @@ +// 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. + +// This file is for including headers that are not included in any other .cc +// files contained with the ui/gfx module. We need to include these here so +// that linker will know to include the symbols, defined by these headers, in +// the resulting dynamic library (gfx.dll). + +#include "ui/gfx/vsync_provider.h" diff --git a/chromium/ui/gfx/utf16_indexing.cc b/chromium/ui/gfx/utf16_indexing.cc index 6af10c18499..c7f38de0d11 100644 --- a/chromium/ui/gfx/utf16_indexing.cc +++ b/chromium/ui/gfx/utf16_indexing.cc @@ -9,12 +9,12 @@ namespace gfx { -bool IsValidCodePointIndex(const string16& s, size_t index) { +bool IsValidCodePointIndex(const base::string16& s, size_t index) { return index == 0 || index == s.length() || !(CBU16_IS_TRAIL(s[index]) && CBU16_IS_LEAD(s[index - 1])); } -ptrdiff_t UTF16IndexToOffset(const string16& s, size_t base, size_t pos) { +ptrdiff_t UTF16IndexToOffset(const base::string16& s, size_t base, size_t pos) { // The indices point between UTF-16 words (range 0 to s.length() inclusive). // In order to consistently handle indices that point to the middle of a // surrogate pair, we count the first word in that surrogate pair and not @@ -30,7 +30,9 @@ ptrdiff_t UTF16IndexToOffset(const string16& s, size_t base, size_t pos) { return delta; } -size_t UTF16OffsetToIndex(const string16& s, size_t base, ptrdiff_t offset) { +size_t UTF16OffsetToIndex(const base::string16& s, + size_t base, + ptrdiff_t offset) { DCHECK_LE(base, s.length()); // As in UTF16IndexToOffset, we count the first half of a surrogate pair, not // the second. When stepping from pos to pos+1 we check s[pos:pos+1] == s[pos] diff --git a/chromium/ui/gfx/utf16_indexing.h b/chromium/ui/gfx/utf16_indexing.h index 7f56384299f..4c2b2c19d56 100644 --- a/chromium/ui/gfx/utf16_indexing.h +++ b/chromium/ui/gfx/utf16_indexing.h @@ -12,7 +12,7 @@ namespace gfx { // Returns false if s[index-1] is a high surrogate and s[index] is a low // surrogate, true otherwise. -UI_EXPORT bool IsValidCodePointIndex(const string16& s, size_t index); +GFX_EXPORT bool IsValidCodePointIndex(const base::string16& s, size_t index); // |UTF16IndexToOffset| returns the number of code points between |base| and // |pos| in the given string. |UTF16OffsetToIndex| returns the index that is @@ -37,12 +37,12 @@ UI_EXPORT bool IsValidCodePointIndex(const string16& s, size_t index); // Always, // UTF16IndexToOffset(s, base, UTF16OffsetToIndex(s, base, ofs)) == ofs // UTF16IndexToOffset(s, i, j) == -UTF16IndexToOffset(s, j, i) -UI_EXPORT ptrdiff_t UTF16IndexToOffset(const string16& s, - size_t base, - size_t pos); -UI_EXPORT size_t UTF16OffsetToIndex(const string16& s, - size_t base, - ptrdiff_t offset); +GFX_EXPORT ptrdiff_t UTF16IndexToOffset(const base::string16& s, + size_t base, + size_t pos); +GFX_EXPORT size_t UTF16OffsetToIndex(const base::string16& s, + size_t base, + ptrdiff_t offset); } // namespace gfx diff --git a/chromium/ui/gfx/vector2d.h b/chromium/ui/gfx/vector2d.h index 9494120d26d..8dd76324d1a 100644 --- a/chromium/ui/gfx/vector2d.h +++ b/chromium/ui/gfx/vector2d.h @@ -18,7 +18,7 @@ namespace gfx { -class UI_EXPORT Vector2d { +class GFX_EXPORT Vector2d { public: Vector2d() : x_(0), y_(0) {} Vector2d(int x, int y) : x_(x), y_(y) {} diff --git a/chromium/ui/gfx/vector2d_conversions.h b/chromium/ui/gfx/vector2d_conversions.h index 051092e78fe..509a4567d10 100644 --- a/chromium/ui/gfx/vector2d_conversions.h +++ b/chromium/ui/gfx/vector2d_conversions.h @@ -11,13 +11,13 @@ namespace gfx { // Returns a Vector2d with each component from the input Vector2dF floored. -UI_EXPORT Vector2d ToFlooredVector2d(const Vector2dF& vector2d); +GFX_EXPORT Vector2d ToFlooredVector2d(const Vector2dF& vector2d); // Returns a Vector2d with each component from the input Vector2dF ceiled. -UI_EXPORT Vector2d ToCeiledVector2d(const Vector2dF& vector2d); +GFX_EXPORT Vector2d ToCeiledVector2d(const Vector2dF& vector2d); // Returns a Vector2d with each component from the input Vector2dF rounded. -UI_EXPORT Vector2d ToRoundedVector2d(const Vector2dF& vector2d); +GFX_EXPORT Vector2d ToRoundedVector2d(const Vector2dF& vector2d); } // namespace gfx diff --git a/chromium/ui/gfx/vector2d_f.h b/chromium/ui/gfx/vector2d_f.h index ebd0b5b4fb5..289b9b7a8d1 100644 --- a/chromium/ui/gfx/vector2d_f.h +++ b/chromium/ui/gfx/vector2d_f.h @@ -16,7 +16,7 @@ namespace gfx { -class UI_EXPORT Vector2dF { +class GFX_EXPORT Vector2dF { public: Vector2dF() : x_(0), y_(0) {} Vector2dF(float x, float y) : x_(x), y_(y) {} @@ -91,16 +91,16 @@ inline Vector2dF operator-(const Vector2dF& lhs, const Vector2dF& rhs) { } // Return the cross product of two vectors. -UI_EXPORT double CrossProduct(const Vector2dF& lhs, const Vector2dF& rhs); +GFX_EXPORT double CrossProduct(const Vector2dF& lhs, const Vector2dF& rhs); // Return the dot product of two vectors. -UI_EXPORT double DotProduct(const Vector2dF& lhs, const Vector2dF& rhs); +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. -UI_EXPORT Vector2dF ScaleVector2d(const Vector2dF& v, - float x_scale, - float y_scale); +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) { diff --git a/chromium/ui/gfx/vector3d_f.h b/chromium/ui/gfx/vector3d_f.h index aaa415b53bd..0e91a362eca 100644 --- a/chromium/ui/gfx/vector3d_f.h +++ b/chromium/ui/gfx/vector3d_f.h @@ -17,7 +17,7 @@ namespace gfx { -class UI_EXPORT Vector3dF { +class GFX_EXPORT Vector3dF { public: Vector3dF(); Vector3dF(float x, float y, float z); @@ -105,14 +105,14 @@ inline Vector3dF CrossProduct(const Vector3dF& lhs, const Vector3dF& rhs) { } // Return the dot product of two vectors. -UI_EXPORT float DotProduct(const Vector3dF& lhs, const Vector3dF& rhs); +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. -UI_EXPORT Vector3dF ScaleVector3d(const Vector3dF& v, - float x_scale, - float y_scale, - float z_scale); +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) { diff --git a/chromium/ui/gfx/vsync_provider.h b/chromium/ui/gfx/vsync_provider.h new file mode 100644 index 00000000000..90464bcbf68 --- /dev/null +++ b/chromium/ui/gfx/vsync_provider.h @@ -0,0 +1,33 @@ +// 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_VSYNC_PROVIDER_H_ +#define UI_GFX_VSYNC_PROVIDER_H_ + +#include "base/callback.h" +#include "base/time/time.h" +#include "ui/gfx/gfx_export.h" + +namespace gfx { + +class GFX_EXPORT VSyncProvider { + public: + virtual ~VSyncProvider() {} + + typedef base::Callback< + void(const base::TimeTicks timebase, const base::TimeDelta interval)> + UpdateVSyncCallback; + + // Get the time of the most recent screen refresh, along with the time + // between consecutive refreshes. The callback is called as soon as + // the data is available: it could be immediately from this method, + // later via a PostTask to the current MessageLoop, or never (if we have + // no data source). We provide the strong guarantee that the callback will + // not be called once the instance of this class is destroyed. + virtual void GetVSyncParameters(const UpdateVSyncCallback& callback) = 0; +}; + +} // namespace gfx + +#endif // UI_GFX_VSYNC_PROVIDER_H_ diff --git a/chromium/ui/gfx/win/dpi.cc b/chromium/ui/gfx/win/dpi.cc index 98d23bd5ef9..6bc25dee646 100644 --- a/chromium/ui/gfx/win/dpi.cc +++ b/chromium/ui/gfx/win/dpi.cc @@ -8,7 +8,6 @@ #include "base/command_line.h" #include "base/win/scoped_hdc.h" #include "base/win/windows_version.h" -#include "ui/base/layout.h" #include "base/win/registry.h" #include "ui/gfx/display.h" #include "ui/gfx/switches.h" @@ -21,31 +20,6 @@ namespace { int kDefaultDPIX = 96; int kDefaultDPIY = 96; -// Tests to see if the command line flag "--high-dpi-support" is set. -bool IsHighDPIEnabled() { - // Default is disabled. - if (CommandLine::ForCurrentProcess()->HasSwitch( - switches::kHighDPISupport)) { - return CommandLine::ForCurrentProcess()->GetSwitchValueASCII( - switches::kHighDPISupport).compare("1") == 0; - } - return false; -} - -// Gets the device scale factor. If support is enabled, this will return the -// best available scale based on the screen's pixel density. This can be -// affected (overridden) by --force-device-scale-factor=x -float GetDeviceScaleFactorImpl() { - if (IsHighDPIEnabled()) { - float scale = gfx::Display::HasForceDeviceScaleFactor() ? - gfx::Display::GetForcedDeviceScaleFactor() : gfx::GetDPIScale(); - // Quantize to nearest supported scale factor. - scale = ui::GetScaleFactorScale(ui::GetScaleFactorFromScale(scale)); - return scale; - } - return 1.0f; -} - BOOL IsProcessDPIAwareWrapper() { typedef BOOL(WINAPI *IsProcessDPIAwarePtr)(VOID); IsProcessDPIAwarePtr is_process_dpi_aware_func = @@ -56,10 +30,41 @@ BOOL IsProcessDPIAwareWrapper() { return FALSE; } +float g_device_scale_factor = 0.0f; + +float GetUnforcedDeviceScaleFactor() { + 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); + } + return result; +} + } // namespace namespace gfx { +float GetModernUIScale() { + return GetModernUIScaleWrapper(); +} + +void InitDeviceScaleFactor(float scale) { + DCHECK_NE(0.0f, scale); + g_device_scale_factor = scale; +} + Size GetDPI() { static int dpi_x = 0; static int dpi_y = 0; @@ -79,18 +84,30 @@ Size GetDPI() { float GetDPIScale() { if (IsHighDPIEnabled()) { - return static_cast<float>(GetDPI().width()) / - static_cast<float>(kDefaultDPIX); + return gfx::Display::HasForceDeviceScaleFactor() ? + gfx::Display::GetForcedDeviceScaleFactor() : + GetUnforcedDeviceScaleFactor(); } return 1.0; } +bool IsHighDPIEnabled() { + // Default is disabled. + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kHighDPISupport)) { + return CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kHighDPISupport).compare("1") == 0; + } + return false; +} + bool IsInHighDPIMode() { return GetDPIScale() > 1.0; } void EnableHighDPISupport() { - if (IsHighDPIEnabled()) { + if (IsHighDPIEnabled() && + (base::win::GetVersion() < base::win::VERSION_WIN8_1)) { typedef BOOL(WINAPI *SetProcessDPIAwarePtr)(VOID); SetProcessDPIAwarePtr set_process_dpi_aware_func = reinterpret_cast<SetProcessDPIAwarePtr>( @@ -104,12 +121,17 @@ void EnableHighDPISupport() { namespace win { float GetDeviceScaleFactor() { - static const float device_scale_factor = GetDeviceScaleFactorImpl(); - return device_scale_factor; + DCHECK_NE(0.0f, g_device_scale_factor); + return g_device_scale_factor; } Point ScreenToDIPPoint(const Point& pixel_point) { - return ToFlooredPoint(ScalePoint(pixel_point, 1.0f / GetDeviceScaleFactor())); + static float scaling_factor = + GetDeviceScaleFactor() > GetUnforcedDeviceScaleFactor() ? + 1.0f / GetDeviceScaleFactor() : + 1.0f; + return ToFlooredPoint(ScalePoint(pixel_point, + scaling_factor)); } Point DIPToScreenPoint(const Point& dip_point) { @@ -162,7 +184,6 @@ double GetUndocumentedDPIScale() { return scale; } - double GetUndocumentedDPITouchScale() { static double scale = (base::win::GetVersion() < base::win::VERSION_WIN8_1) ? @@ -170,6 +191,5 @@ double GetUndocumentedDPITouchScale() { return scale; } - } // namespace win } // namespace gfx diff --git a/chromium/ui/gfx/win/dpi.h b/chromium/ui/gfx/win/dpi.h index a056f532661..772944f50f9 100644 --- a/chromium/ui/gfx/win/dpi.h +++ b/chromium/ui/gfx/win/dpi.h @@ -12,37 +12,52 @@ namespace gfx { -UI_EXPORT Size GetDPI(); +// Initialization of the scale factor that should be applied for rendering +// in this process. Must be called before attempts to call any of the getter +// methods below in this file, e.g. in the early toolkit/resource bundle setup. +// This can be called multiple times during various tests, but subsequent calls +// have no effect. +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. -UI_EXPORT float GetDPIScale(); +// 96 then the scale factor is 1.0. Note that this is the "desktop" scale, which +// may be differnt than GetModernUIScale(). +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(); -UI_EXPORT bool IsInHighDPIMode(); +GFX_EXPORT bool IsInHighDPIMode(); -UI_EXPORT void EnableHighDPISupport(); +GFX_EXPORT void EnableHighDPISupport(); // TODO(kevers|girard): Move above methods into win namespace. namespace win { -UI_EXPORT float GetDeviceScaleFactor(); +GFX_EXPORT float GetDeviceScaleFactor(); -UI_EXPORT Point ScreenToDIPPoint(const Point& pixel_point); +GFX_EXPORT Point ScreenToDIPPoint(const Point& pixel_point); -UI_EXPORT Point DIPToScreenPoint(const Point& dip_point); +GFX_EXPORT Point DIPToScreenPoint(const Point& dip_point); -UI_EXPORT Rect ScreenToDIPRect(const Rect& pixel_bounds); +GFX_EXPORT Rect ScreenToDIPRect(const Rect& pixel_bounds); -UI_EXPORT Rect DIPToScreenRect(const Rect& dip_bounds); +GFX_EXPORT Rect DIPToScreenRect(const Rect& dip_bounds); -UI_EXPORT Size ScreenToDIPSize(const Size& size_in_pixels); +GFX_EXPORT Size ScreenToDIPSize(const Size& size_in_pixels); -UI_EXPORT Size DIPToScreenSize(const Size& dip_size); +GFX_EXPORT Size DIPToScreenSize(const Size& dip_size); // Win32's GetSystemMetrics uses pixel measures. This function calls // GetSystemMetrics for the given |metric|, then converts the result to DIP. -UI_EXPORT int GetSystemMetricsInDIP(int metric); +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 @@ -50,12 +65,12 @@ UI_EXPORT int GetSystemMetricsInDIP(int metric); // 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 -UI_EXPORT double GetUndocumentedDPIScale(); +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. -UI_EXPORT double GetUndocumentedDPITouchScale(); +GFX_EXPORT double GetUndocumentedDPITouchScale(); } // namespace win } // namespace gfx diff --git a/chromium/ui/gfx/win/hwnd_util.cc b/chromium/ui/gfx/win/hwnd_util.cc index 91f0ddd182a..fec39d4fe59 100644 --- a/chromium/ui/gfx/win/hwnd_util.cc +++ b/chromium/ui/gfx/win/hwnd_util.cc @@ -50,6 +50,24 @@ void AdjustWindowToFit(HWND hwnd, const RECT& bounds, bool fit_to_monitor) { SWP_NOACTIVATE | SWP_NOZORDER); } +// Turn off optimizations for these functions so they show up in crash reports. +MSVC_DISABLE_OPTIMIZE(); + +void CrashOutOfMemory() { + LOG_GETLASTERROR(FATAL); +} + +void CrashAccessDenied() { + LOG_GETLASTERROR(FATAL); +} + +// Crash isn't one of the ones we commonly see. +void CrashOther() { + LOG_GETLASTERROR(FATAL); +} + +MSVC_ENABLE_OPTIMIZE(); + } // namespace string16 GetClassName(HWND window) { @@ -170,8 +188,20 @@ void CenterAndSizeWindow(HWND parent, } void CheckWindowCreated(HWND hwnd) { - if (!hwnd) + if (!hwnd) { + switch (GetLastError()) { + case ERROR_NOT_ENOUGH_MEMORY: + CrashOutOfMemory(); + break; + case ERROR_ACCESS_DENIED: + CrashAccessDenied(); + break; + default: + CrashOther(); + break; + } LOG_GETLASTERROR(FATAL); + } } void ShowSystemMenu(HWND window) { diff --git a/chromium/ui/gfx/win/hwnd_util.h b/chromium/ui/gfx/win/hwnd_util.h index 70e5f8f1c2b..472daccd82e 100644 --- a/chromium/ui/gfx/win/hwnd_util.h +++ b/chromium/ui/gfx/win/hwnd_util.h @@ -16,38 +16,38 @@ 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. -UI_EXPORT string16 GetClassName(HWND hwnd); +GFX_EXPORT string16 GetClassName(HWND hwnd); // Useful for subclassing a HWND. Returns the previous window procedure. -UI_EXPORT WNDPROC SetWindowProc(HWND hwnd, WNDPROC wndproc); +GFX_EXPORT WNDPROC SetWindowProc(HWND hwnd, WNDPROC wndproc); // Pointer-friendly wrappers around Get/SetWindowLong(..., GWLP_USERDATA, ...) // Returns the previously set value. -UI_EXPORT void* SetWindowUserData(HWND hwnd, void* user_data); -UI_EXPORT void* GetWindowUserData(HWND hwnd); +GFX_EXPORT void* SetWindowUserData(HWND hwnd, void* user_data); +GFX_EXPORT void* GetWindowUserData(HWND hwnd); // Returns true if the specified window is the current active top window or one // of its children. -UI_EXPORT bool DoesWindowBelongToActiveWindow(HWND window); +GFX_EXPORT bool DoesWindowBelongToActiveWindow(HWND window); // Sizes the window to have a window size of |pref|, then centers the window // over |parent|, ensuring the window fits on screen. -UI_EXPORT void CenterAndSizeWindow(HWND parent, - HWND window, - const gfx::Size& pref); +GFX_EXPORT void CenterAndSizeWindow(HWND parent, + HWND window, + const gfx::Size& pref); // If |hwnd| is NULL logs various thing and CHECKs. Invoke right after calling // CreateWindow. -UI_EXPORT void CheckWindowCreated(HWND hwnd); +GFX_EXPORT void CheckWindowCreated(HWND hwnd); // Shows |window|'s system menu (at a specified |point| in screen coordinates). -UI_EXPORT void ShowSystemMenu(HWND window); -UI_EXPORT void ShowSystemMenuAtPoint(HWND window, const gfx::Point& point); +GFX_EXPORT void ShowSystemMenu(HWND window); +GFX_EXPORT void ShowSystemMenuAtPoint(HWND window, const gfx::Point& point); // Returns the window you can use to parent a top level window. // Note that in some cases we create child windows not parented to its final // container so in those cases you should pass true in |get_real_hwnd|. -UI_EXPORT HWND GetWindowToParentTo(bool get_real_hwnd); +GFX_EXPORT HWND GetWindowToParentTo(bool get_real_hwnd); } // namespace gfx diff --git a/chromium/ui/gfx/win/singleton_hwnd.cc b/chromium/ui/gfx/win/singleton_hwnd.cc index 37993e8f4f0..2de6a8b8a16 100644 --- a/chromium/ui/gfx/win/singleton_hwnd.cc +++ b/chromium/ui/gfx/win/singleton_hwnd.cc @@ -15,16 +15,6 @@ SingletonHwnd* SingletonHwnd::GetInstance() { } void SingletonHwnd::AddObserver(Observer* observer) { - if (!hwnd()) { - if (!base::MessageLoop::current() || - base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { - // 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!"; - return; - } - WindowImpl::Init(NULL, Rect()); - } observer_list_.AddObserver(observer); } @@ -47,6 +37,14 @@ BOOL SingletonHwnd::ProcessWindowMessage(HWND window, } SingletonHwnd::SingletonHwnd() { + if (!base::MessageLoop::current() || + base::MessageLoop::current()->type() != base::MessageLoop::TYPE_UI) { + // 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!"; + return; + } + WindowImpl::Init(NULL, Rect()); } SingletonHwnd::~SingletonHwnd() { diff --git a/chromium/ui/gfx/win/singleton_hwnd.h b/chromium/ui/gfx/win/singleton_hwnd.h index 96af6e79205..50fb9fd9df9 100644 --- a/chromium/ui/gfx/win/singleton_hwnd.h +++ b/chromium/ui/gfx/win/singleton_hwnd.h @@ -19,7 +19,7 @@ namespace gfx { // Singleton message-only HWND that allows interested clients to receive WM_* // notifications. -class SingletonHwnd : public WindowImpl { +class GFX_EXPORT SingletonHwnd : public WindowImpl { public: static SingletonHwnd* GetInstance(); diff --git a/chromium/ui/gfx/win/window_impl.cc b/chromium/ui/gfx/win/window_impl.cc index e2e6af05c61..7f0c232ae61 100644 --- a/chromium/ui/gfx/win/window_impl.cc +++ b/chromium/ui/gfx/win/window_impl.cc @@ -108,7 +108,7 @@ ATOM ClassRegistrar::RetrieveClassAtom(const ClassInfo& class_info) { 0, 0, NULL, - NULL, + reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH)), NULL, class_info.icon, class_info.icon, diff --git a/chromium/ui/gfx/win/window_impl.h b/chromium/ui/gfx/win/window_impl.h index 2b0018e3f46..1825c0b2f00 100644 --- a/chromium/ui/gfx/win/window_impl.h +++ b/chromium/ui/gfx/win/window_impl.h @@ -40,7 +40,7 @@ class MessageMapInterface { // Windows. // /////////////////////////////////////////////////////////////////////////////// -class UI_EXPORT WindowImpl : public MessageMapInterface { +class GFX_EXPORT WindowImpl : public MessageMapInterface { public: WindowImpl(); virtual ~WindowImpl(); diff --git a/chromium/ui/gfx/x/x11_atom_cache.cc b/chromium/ui/gfx/x/x11_atom_cache.cc new file mode 100644 index 00000000000..da75c0be34e --- /dev/null +++ b/chromium/ui/gfx/x/x11_atom_cache.cc @@ -0,0 +1,47 @@ +// 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/x/x11_atom_cache.h" + +#include <X11/Xatom.h> + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" + +namespace ui { + +X11AtomCache::X11AtomCache(Display* 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]); + + // Grab all the atoms we need now to minimize roundtrips to the X11 server. + XInternAtoms(xdisplay_, + const_cast<char**>(to_cache), cache_count, False, + cached_atoms.get()); + + for (int i = 0; i < cache_count; ++i) + cached_atoms_.insert(std::make_pair(to_cache[i], cached_atoms[i])); +} + +X11AtomCache::~X11AtomCache() {} + +::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); + cached_atoms_.insert(std::make_pair(name, atom)); + return atom; + } + + CHECK(it != cached_atoms_.end()) << " Atom " << name << " not found"; + return it->second; +} + +} // namespace ui diff --git a/chromium/ui/gfx/x/x11_atom_cache.h b/chromium/ui/gfx/x/x11_atom_cache.h new file mode 100644 index 00000000000..fefa64205d0 --- /dev/null +++ b/chromium/ui/gfx/x/x11_atom_cache.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_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> + +// Get rid of a macro from Xlib.h that conflicts with Aura's RootWindow class. +#undef RootWindow + +namespace ui { + +// Pre-caches all Atoms on first use to minimize roundtrips to the X11 +// server. By default, GetAtom() will CHECK() that atoms accessed through +// GetAtom() were passed to the constructor, but this behaviour can be changed +// with allow_uncached_atoms(). +class GFX_EXPORT X11AtomCache { + public: + // Preinterns the NULL terminated list of string |to_cache_ on |xdisplay|. + X11AtomCache(Display* xdisplay, const char** to_cache); + ~X11AtomCache(); + + // Returns the pre-interned Atom without having to go to the x server. + ::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_; + + bool uncached_atoms_allowed_; + + mutable std::map<std::string, ::Atom> cached_atoms_; + + DISALLOW_COPY_AND_ASSIGN(X11AtomCache); +}; + +} // namespace ui + +#endif // UI_GFX_X_X11_ATOM_CACHE_H_ diff --git a/chromium/ui/gfx/x/x11_types.cc b/chromium/ui/gfx/x/x11_types.cc index c47c852527b..48ce6416b69 100644 --- a/chromium/ui/gfx/x/x11_types.cc +++ b/chromium/ui/gfx/x/x11_types.cc @@ -4,6 +4,8 @@ #include "ui/gfx/x/x11_types.h" +#include <X11/Xlib.h> + #include "base/message_loop/message_loop.h" namespace gfx { @@ -12,5 +14,142 @@ XDisplay* GetXDisplay() { return base::MessagePumpForUI::GetDefaultXDisplay(); } +void PutARGBImage(XDisplay* display, + void* visual, int depth, + XID pixmap, void* pixmap_gc, + const uint8* data, + int width, int height) { + PutARGBImage(display, + visual, depth, + pixmap, pixmap_gc, + data, width, height, + 0, 0, // src_x, src_y + 0, 0, // dst_x, dst_y + width, height); +} + +int BitsPerPixelForPixmapDepth(XDisplay* dpy, int depth) { + int count; + XPixmapFormatValues* formats = XListPixmapFormats(dpy, &count); + if (!formats) + return -1; + + int bits_per_pixel = -1; + for (int i = 0; i < count; ++i) { + if (formats[i].depth == depth) { + bits_per_pixel = formats[i].bits_per_pixel; + break; + } + } + + XFree(formats); + return bits_per_pixel; +} + +void PutARGBImage(XDisplay* display, + void* visual, int depth, + XID pixmap, void* pixmap_gc, + const uint8* data, + int data_width, int data_height, + int src_x, int src_y, + int dst_x, int dst_y, + int copy_width, int copy_height) { + // TODO(scherkus): potential performance impact... consider passing in as a + // parameter. + int pixmap_bpp = BitsPerPixelForPixmapDepth(display, depth); + + XImage image; + memset(&image, 0, sizeof(image)); + + image.width = data_width; + image.height = data_height; + image.format = ZPixmap; + image.byte_order = LSBFirst; + image.bitmap_unit = 8; + image.bitmap_bit_order = LSBFirst; + image.depth = depth; + image.bits_per_pixel = pixmap_bpp; + image.bytes_per_line = data_width * pixmap_bpp / 8; + + if (pixmap_bpp == 32) { + image.red_mask = 0xff0000; + image.green_mask = 0xff00; + image.blue_mask = 0xff; + + // If the X server depth is already 32-bits and the color masks match, + // then our job is easy. + Visual* vis = static_cast<Visual*>(visual); + if (image.red_mask == vis->red_mask && + image.green_mask == vis->green_mask && + image.blue_mask == vis->blue_mask) { + image.data = const_cast<char*>(reinterpret_cast<const char*>(data)); + XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image, + src_x, src_y, dst_x, dst_y, + copy_width, copy_height); + } else { + // Otherwise, we need to shuffle the colors around. Assume red and blue + // need to be swapped. + // + // It's possible to use some fancy SSE tricks here, but since this is the + // slow path anyway, we do it slowly. + + uint8_t* bitmap32 = + static_cast<uint8_t*>(malloc(4 * data_width * data_height)); + if (!bitmap32) + return; + uint8_t* const orig_bitmap32 = bitmap32; + const uint32_t* bitmap_in = reinterpret_cast<const uint32_t*>(data); + for (int y = 0; y < data_height; ++y) { + for (int x = 0; x < data_width; ++x) { + const uint32_t pixel = *(bitmap_in++); + bitmap32[0] = (pixel >> 16) & 0xff; // Red + bitmap32[1] = (pixel >> 8) & 0xff; // Green + bitmap32[2] = pixel & 0xff; // Blue + bitmap32[3] = (pixel >> 24) & 0xff; // Alpha + bitmap32 += 4; + } + } + image.data = reinterpret_cast<char*>(orig_bitmap32); + XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image, + src_x, src_y, dst_x, dst_y, + copy_width, copy_height); + free(orig_bitmap32); + } + } else if (pixmap_bpp == 16) { + // Some folks have VNC setups which still use 16-bit visuals and VNC + // doesn't include Xrender. + + uint16_t* bitmap16 = + static_cast<uint16_t*>(malloc(2 * data_width * data_height)); + if (!bitmap16) + return; + uint16_t* const orig_bitmap16 = bitmap16; + const uint32_t* bitmap_in = reinterpret_cast<const uint32_t*>(data); + for (int y = 0; y < data_height; ++y) { + for (int x = 0; x < data_width; ++x) { + const uint32_t pixel = *(bitmap_in++); + uint16_t out_pixel = ((pixel >> 8) & 0xf800) | + ((pixel >> 5) & 0x07e0) | + ((pixel >> 3) & 0x001f); + *(bitmap16++) = out_pixel; + } + } + + image.data = reinterpret_cast<char*>(orig_bitmap16); + image.red_mask = 0xf800; + image.green_mask = 0x07e0; + image.blue_mask = 0x001f; + + XPutImage(display, pixmap, static_cast<GC>(pixmap_gc), &image, + src_x, src_y, dst_x, dst_y, + copy_width, copy_height); + free(orig_bitmap16); + } else { + LOG(FATAL) << "Sorry, we don't support your visual depth without " + "Xrender support (depth:" << depth + << " bpp:" << pixmap_bpp << ")"; + } +} + } // namespace gfx diff --git a/chromium/ui/gfx/x/x11_types.h b/chromium/ui/gfx/x/x11_types.h index eab42f2352b..0f96fdc6a89 100644 --- a/chromium/ui/gfx/x/x11_types.h +++ b/chromium/ui/gfx/x/x11_types.h @@ -5,6 +5,7 @@ #ifndef UI_GFX_X_X11_UTIL_H_ #define UI_GFX_X_X11_UTIL_H_ +#include "base/basictypes.h" #include "ui/gfx/gfx_export.h" typedef unsigned long XID; @@ -19,6 +20,32 @@ namespace gfx { // chrome codebase to get the display from window. GFX_EXPORT XDisplay* GetXDisplay(); +// Return the number of bits-per-pixel for a pixmap of the given depth +GFX_EXPORT int BitsPerPixelForPixmapDepth(XDisplay* display, int depth); + +// Draws ARGB data on the given pixmap using the given GC, converting to the +// server side visual depth as needed. Destination is assumed to be the same +// dimensions as |data| or larger. |data| is also assumed to be in row order +// with each line being exactly |width| * 4 bytes long. +GFX_EXPORT void PutARGBImage(XDisplay* display, + void* visual, int depth, + XID pixmap, void* pixmap_gc, + const uint8* data, + int width, int height); + +// Same as above only more general: +// - |data_width| and |data_height| refer to the data image +// - |src_x|, |src_y|, |copy_width| and |copy_height| define source region +// - |dst_x|, |dst_y|, |copy_width| and |copy_height| define destination region +GFX_EXPORT void PutARGBImage(XDisplay* display, + void* visual, int depth, + XID pixmap, void* pixmap_gc, + const uint8* data, + int data_width, int data_height, + int src_x, int src_y, + int dst_x, int dst_y, + int copy_width, int copy_height); + } // namespace gfx #endif // UI_GFX_X_X11_UTIL_H_ |