Chromium Code Reviews| Index: chrome/browser/autocomplete/autocomplete_edit.cc |
| diff --git a/chrome/browser/autocomplete/autocomplete_edit.cc b/chrome/browser/autocomplete/autocomplete_edit.cc |
| index b332832f8e9395f737795c803dc7c1df5b9ea913..395deec816e9a9a0aaf99516910723726d96feb3 100644 |
| --- a/chrome/browser/autocomplete/autocomplete_edit.cc |
| +++ b/chrome/browser/autocomplete/autocomplete_edit.cc |
| @@ -9,6 +9,7 @@ |
| #include "base/base_drag_source.h" |
| #include "base/clipboard.h" |
| #include "base/iat_patch.h" |
| +#include "base/lazy_instance.h" |
| #include "base/ref_counted.h" |
| #include "base/scoped_clipboard_writer.h" |
| #include "base/string_util.h" |
| @@ -633,26 +634,79 @@ AutocompleteEditView::ScopedSuspendUndo::~ScopedSuspendUndo() { |
| // TODO (jcampan): these colors should be derived from the system colors to |
| // ensure they show properly. Bug #948807. |
| // Colors used to emphasize the scheme in the URL. |
| -static const COLORREF kSecureSchemeColor = RGB(0, 150, 20); |
| -static const COLORREF kInsecureSchemeColor = RGB(200, 0, 0); |
| + |
| +namespace { |
| + |
| +const COLORREF kSecureSchemeColor = RGB(0, 150, 20); |
| +const COLORREF kInsecureSchemeColor = RGB(200, 0, 0); |
| // Colors used to strike-out the scheme when it is insecure. |
| -static const SkColor kSchemeStrikeoutColor = SkColorSetRGB(210, 0, 0); |
| -static const SkColor kSchemeSelectedStrikeoutColor = |
| +const SkColor kSchemeStrikeoutColor = SkColorSetRGB(210, 0, 0); |
| +const SkColor kSchemeSelectedStrikeoutColor = |
| SkColorSetRGB(255, 255, 255); |
| // These are used to hook the CRichEditCtrl's calls to BeginPaint() and |
| // EndPaint() and provide a memory DC instead. See OnPaint(). |
| -static HWND edit_hwnd = NULL; |
| -static PAINTSTRUCT paint_struct; |
| +HWND edit_hwnd = NULL; |
| +PAINTSTRUCT paint_struct; |
| + |
| +HDC BeginPaintIntercept(HWND hWnd, LPPAINTSTRUCT lpPaint) { |
| + if (!edit_hwnd || (hWnd != edit_hwnd)) |
| + return ::BeginPaint(hWnd, lpPaint); |
| + |
| + *lpPaint = paint_struct; |
| + return paint_struct.hdc; |
| +} |
| + |
| +BOOL EndPaintIntercept(HWND hWnd, const PAINTSTRUCT* lpPaint) { |
| + return (edit_hwnd && (hWnd == edit_hwnd)) ? |
| + true : ::EndPaint(hWnd, lpPaint); |
| +} |
| // Returns a lazily initialized property bag accessor for saving our state in a |
| // TabContents. |
| -static PropertyAccessor<AutocompleteEditState>* GetStateAccessor() { |
| +PropertyAccessor<AutocompleteEditState>* GetStateAccessor() { |
| static PropertyAccessor<AutocompleteEditState> state; |
| return &state; |
| } |
| +class PaintPatcher { |
|
amit
2009/02/26 15:00:32
maybe derive privately from RefCounted and just ca
|
| + public: |
| + PaintPatcher() : refcount_(0) { } |
| + ~PaintPatcher() { DCHECK(refcount_ == 0); } |
| + |
| + void RefPatch() { |
| + if (refcount_ == 0) { |
| + DCHECK(!begin_paint_.is_patched()); |
| + DCHECK(!end_paint_.is_patched()); |
| + begin_paint_.Patch(L"riched20.dll", "user32.dll", "BeginPaint", |
| + &BeginPaintIntercept); |
| + end_paint_.Patch(L"riched20.dll", "user32.dll", "EndPaint", |
| + &EndPaintIntercept); |
| + } |
| + ++refcount_; |
| + } |
| + |
| + void DerefPatch() { |
| + DCHECK(begin_paint_.is_patched()); |
| + DCHECK(end_paint_.is_patched()); |
| + --refcount_; |
| + if (refcount_ == 0) { |
| + begin_paint_.Unpatch(); |
| + end_paint_.Unpatch(); |
| + } |
| + } |
| + |
| + private: |
|
amit
2009/02/26 15:00:32
DISABLE_COPY_AND_ASSIGN
|
| + size_t refcount_; |
| + iat_patch::IATPatchFunction begin_paint_; |
| + iat_patch::IATPatchFunction end_paint_; |
| +}; |
| + |
| +base::LazyInstance<PaintPatcher> g_paint_patcher(base::LINKER_INITIALIZED); |
| + |
| +} // namespace |
| + |
| AutocompleteEditView::AutocompleteEditView( |
| const ChromeFont& font, |
| AutocompleteEditController* controller, |
| @@ -685,22 +739,7 @@ AutocompleteEditView::AutocompleteEditView( |
| saved_selection_for_focus_change_.cpMin = -1; |
| - // Statics used for global patching of riched20.dll. |
| - static HMODULE richedit_module = NULL; |
| - static iat_patch::IATPatchFunction patch_begin_paint; |
| - static iat_patch::IATPatchFunction patch_end_paint; |
| - |
| - if (!richedit_module) { |
| - richedit_module = LoadLibrary(L"riched20.dll"); |
| - if (richedit_module) { |
| - DCHECK(!patch_begin_paint.is_patched()); |
| - patch_begin_paint.Patch(richedit_module, "user32.dll", "BeginPaint", |
| - &BeginPaintIntercept); |
| - DCHECK(!patch_end_paint.is_patched()); |
| - patch_end_paint.Patch(richedit_module, "user32.dll", "EndPaint", |
| - &EndPaintIntercept); |
| - } |
| - } |
| + g_paint_patcher.Pointer()->RefPatch(); |
| Create(hwnd, 0, 0, 0, l10n_util::GetExtendedStyles()); |
| SetReadOnly(popup_window_mode_); |
| @@ -787,6 +826,11 @@ AutocompleteEditView::~AutocompleteEditView() { |
| NotificationType::AUTOCOMPLETE_EDIT_DESTROYED, |
| Source<AutocompleteEditView>(this), |
| NotificationService::NoDetails()); |
| + |
| + // We balance our reference count and unpatch when the last instance has |
| + // been destroyed. This prevents us from relying on the AtExit or static |
| + // destructor sequence to do our unpatching, which is generally fragile. |
| + g_paint_patcher.Pointer()->DerefPatch(); |
| } |
| void AutocompleteEditView::SaveStateToTab(TabContents* tab) { |
| @@ -1374,23 +1418,6 @@ bool AutocompleteEditView::SchemeEnd(LPTSTR edit_text, |
| (edit_text[current_pos + 2] == '/'); |
| } |
| -// static |
| -HDC AutocompleteEditView::BeginPaintIntercept(HWND hWnd, |
| - LPPAINTSTRUCT lpPaint) { |
| - if (!edit_hwnd || (hWnd != edit_hwnd)) |
| - return ::BeginPaint(hWnd, lpPaint); |
| - |
| - *lpPaint = paint_struct; |
| - return paint_struct.hdc; |
| -} |
| - |
| -// static |
| -BOOL AutocompleteEditView::EndPaintIntercept(HWND hWnd, |
| - const PAINTSTRUCT* lpPaint) { |
| - return (edit_hwnd && (hWnd == edit_hwnd)) ? |
| - true : ::EndPaint(hWnd, lpPaint); |
| -} |
| - |
| void AutocompleteEditView::OnChar(TCHAR ch, UINT repeat_count, UINT flags) { |
| // Don't let alt-enter beep. Not sure this is necessary, as the standard |
| // alt-enter will hit DiscardWMSysChar() and get thrown away, and |