Commit f28021f2 authored by kundaji's avatar kundaji Committed by Commit bot

Context menu to view original image when Data Saver is being used.

Show menu item to view original image if the request could go over
the data reduction proxy.

BUG=456247

Review URL: https://codereview.chromium.org/944533002

Cr-Commit-Position: refs/heads/master@{#317720}
parent dfffe67c
......@@ -279,6 +279,7 @@
#define IDC_CONTENT_CONTEXT_COPYIMAGE 50112
#define IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB 50113
#define IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE 50114
#define IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB 50115
// Audio/video items.
#define IDC_CONTENT_CONTEXT_SAVEAVAS 50120
#define IDC_CONTENT_CONTEXT_COPYAVLOCATION 50121
......
......@@ -31,6 +31,8 @@
#include "chrome/browser/download/download_stats.h"
#include "chrome/browser/extensions/devtools_util.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h"
#include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.h"
#include "chrome/browser/plugins/chrome_plugin_service_filter.h"
#include "chrome/browser/prefs/incognito_mode_prefs.h"
#include "chrome/browser/profiles/profile.h"
......@@ -148,69 +150,70 @@ const struct UmaEnumCommandIdPair {
int enum_id;
int control_id;
} kUmaEnumToControlId[] = {
/*
enum id for 0, 1 are detected using
RenderViewContextMenu::IsContentCustomCommandId and
ContextMenuMatcher::IsExtensionsCustomCommandId
*/
{2, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST},
{3, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB},
{4, IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW},
{5, IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD},
{6, IDC_CONTENT_CONTEXT_SAVELINKAS},
{7, IDC_CONTENT_CONTEXT_SAVEAVAS},
{8, IDC_CONTENT_CONTEXT_SAVEIMAGEAS},
{9, IDC_CONTENT_CONTEXT_COPYLINKLOCATION},
{10, IDC_CONTENT_CONTEXT_COPYIMAGELOCATION},
{11, IDC_CONTENT_CONTEXT_COPYAVLOCATION},
{12, IDC_CONTENT_CONTEXT_COPYIMAGE},
{13, IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB},
{14, IDC_CONTENT_CONTEXT_OPENAVNEWTAB},
{15, IDC_CONTENT_CONTEXT_PLAYPAUSE},
{16, IDC_CONTENT_CONTEXT_MUTE},
{17, IDC_CONTENT_CONTEXT_LOOP},
{18, IDC_CONTENT_CONTEXT_CONTROLS},
{19, IDC_CONTENT_CONTEXT_ROTATECW},
{20, IDC_CONTENT_CONTEXT_ROTATECCW},
{21, IDC_BACK},
{22, IDC_FORWARD},
{23, IDC_SAVE_PAGE},
{24, IDC_RELOAD},
{25, IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP},
{26, IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP},
{27, IDC_PRINT},
{28, IDC_VIEW_SOURCE},
{29, IDC_CONTENT_CONTEXT_INSPECTELEMENT},
{30, IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE},
{31, IDC_CONTENT_CONTEXT_VIEWPAGEINFO},
{32, IDC_CONTENT_CONTEXT_TRANSLATE},
{33, IDC_CONTENT_CONTEXT_RELOADFRAME},
{34, IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE},
{35, IDC_CONTENT_CONTEXT_VIEWFRAMEINFO},
{36, IDC_CONTENT_CONTEXT_UNDO},
{37, IDC_CONTENT_CONTEXT_REDO},
{38, IDC_CONTENT_CONTEXT_CUT},
{39, IDC_CONTENT_CONTEXT_COPY},
{40, IDC_CONTENT_CONTEXT_PASTE},
{41, IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE},
{42, IDC_CONTENT_CONTEXT_DELETE},
{43, IDC_CONTENT_CONTEXT_SELECTALL},
{44, IDC_CONTENT_CONTEXT_SEARCHWEBFOR},
{45, IDC_CONTENT_CONTEXT_GOTOURL},
{46, IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS},
{47, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS},
{48, IDC_CONTENT_CONTEXT_ADDSEARCHENGINE},
{52, IDC_CONTENT_CONTEXT_OPENLINKWITH},
{53, IDC_CHECK_SPELLING_WHILE_TYPING},
{54, IDC_SPELLCHECK_MENU},
{55, IDC_CONTENT_CONTEXT_SPELLING_TOGGLE},
{56, IDC_SPELLCHECK_LANGUAGES_FIRST},
{57, IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE},
{58, IDC_SPELLCHECK_SUGGESTION_0},
{59, IDC_SPELLCHECK_ADD_TO_DICTIONARY},
{60, IDC_SPELLPANEL_TOGGLE},
// Add new items here and use |enum_id| from the next line.
{61, 0}, // Must be the last. Increment |enum_id| when new IDC was added.
/*
enum id for 0, 1 are detected using
RenderViewContextMenu::IsContentCustomCommandId and
ContextMenuMatcher::IsExtensionsCustomCommandId
*/
{2, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_FIRST},
{3, IDC_CONTENT_CONTEXT_OPENLINKNEWTAB},
{4, IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW},
{5, IDC_CONTENT_CONTEXT_OPENLINKOFFTHERECORD},
{6, IDC_CONTENT_CONTEXT_SAVELINKAS},
{7, IDC_CONTENT_CONTEXT_SAVEAVAS},
{8, IDC_CONTENT_CONTEXT_SAVEIMAGEAS},
{9, IDC_CONTENT_CONTEXT_COPYLINKLOCATION},
{10, IDC_CONTENT_CONTEXT_COPYIMAGELOCATION},
{11, IDC_CONTENT_CONTEXT_COPYAVLOCATION},
{12, IDC_CONTENT_CONTEXT_COPYIMAGE},
{13, IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB},
{14, IDC_CONTENT_CONTEXT_OPENAVNEWTAB},
{15, IDC_CONTENT_CONTEXT_PLAYPAUSE},
{16, IDC_CONTENT_CONTEXT_MUTE},
{17, IDC_CONTENT_CONTEXT_LOOP},
{18, IDC_CONTENT_CONTEXT_CONTROLS},
{19, IDC_CONTENT_CONTEXT_ROTATECW},
{20, IDC_CONTENT_CONTEXT_ROTATECCW},
{21, IDC_BACK},
{22, IDC_FORWARD},
{23, IDC_SAVE_PAGE},
{24, IDC_RELOAD},
{25, IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP},
{26, IDC_CONTENT_CONTEXT_RESTART_PACKAGED_APP},
{27, IDC_PRINT},
{28, IDC_VIEW_SOURCE},
{29, IDC_CONTENT_CONTEXT_INSPECTELEMENT},
{30, IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE},
{31, IDC_CONTENT_CONTEXT_VIEWPAGEINFO},
{32, IDC_CONTENT_CONTEXT_TRANSLATE},
{33, IDC_CONTENT_CONTEXT_RELOADFRAME},
{34, IDC_CONTENT_CONTEXT_VIEWFRAMESOURCE},
{35, IDC_CONTENT_CONTEXT_VIEWFRAMEINFO},
{36, IDC_CONTENT_CONTEXT_UNDO},
{37, IDC_CONTENT_CONTEXT_REDO},
{38, IDC_CONTENT_CONTEXT_CUT},
{39, IDC_CONTENT_CONTEXT_COPY},
{40, IDC_CONTENT_CONTEXT_PASTE},
{41, IDC_CONTENT_CONTEXT_PASTE_AND_MATCH_STYLE},
{42, IDC_CONTENT_CONTEXT_DELETE},
{43, IDC_CONTENT_CONTEXT_SELECTALL},
{44, IDC_CONTENT_CONTEXT_SEARCHWEBFOR},
{45, IDC_CONTENT_CONTEXT_GOTOURL},
{46, IDC_CONTENT_CONTEXT_LANGUAGE_SETTINGS},
{47, IDC_CONTENT_CONTEXT_PROTOCOL_HANDLER_SETTINGS},
{48, IDC_CONTENT_CONTEXT_ADDSEARCHENGINE},
{52, IDC_CONTENT_CONTEXT_OPENLINKWITH},
{53, IDC_CHECK_SPELLING_WHILE_TYPING},
{54, IDC_SPELLCHECK_MENU},
{55, IDC_CONTENT_CONTEXT_SPELLING_TOGGLE},
{56, IDC_SPELLCHECK_LANGUAGES_FIRST},
{57, IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE},
{58, IDC_SPELLCHECK_SUGGESTION_0},
{59, IDC_SPELLCHECK_ADD_TO_DICTIONARY},
{60, IDC_SPELLPANEL_TOGGLE},
{61, IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB},
// Add new items here and use |enum_id| from the next line.
{62, 0}, // Must be the last. Increment |enum_id| when new IDC was added.
};
// Collapses large ranges of ids before looking for UMA enum.
......@@ -692,8 +695,16 @@ void RenderViewContextMenu::AppendImageItems() {
IDS_CONTENT_CONTEXT_COPYIMAGELOCATION);
menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_COPYIMAGE,
IDS_CONTENT_CONTEXT_COPYIMAGE);
menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB,
IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB);
if (!browser_context_->IsOffTheRecord() &&
DataReductionProxyChromeSettingsFactory::GetForBrowserContext(
browser_context_)->CanUseDataReductionProxy(params_.src_url)) {
menu_model_.AddItemWithStringId(
IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB,
IDS_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB);
} else {
menu_model_.AddItemWithStringId(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB,
IDS_CONTENT_CONTEXT_OPENIMAGENEWTAB);
}
}
void RenderViewContextMenu::AppendSearchWebForImageItems() {
......@@ -1102,6 +1113,7 @@ bool RenderViewContextMenu::IsCommandIdEnabled(int id) const {
// The images shown in the most visited thumbnails can't be opened or
// searched for conventionally.
case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB:
case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
case IDC_CONTENT_CONTEXT_SEARCHWEBFORIMAGE:
return params_.src_url.is_valid() &&
......@@ -1400,6 +1412,13 @@ void RenderViewContextMenu::ExecuteCommand(int id, int event_flags) {
GetImageThumbnailForSearch();
break;
case IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB:
OpenURLWithExtraHeaders(
params_.src_url, GetDocumentURL(params_), NEW_BACKGROUND_TAB,
ui::PAGE_TRANSITION_LINK,
data_reduction_proxy::kDataReductionPassThroughHeader);
break;
case IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB:
case IDC_CONTENT_CONTEXT_OPENAVNEWTAB:
OpenURL(params_.src_url,
......
......@@ -4,6 +4,7 @@
#include <string>
#include "base/command_line.h"
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
......@@ -20,6 +21,7 @@
#include "chrome/common/render_messages.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/data_reduction_proxy/core/common/data_reduction_proxy_switches.h"
#include "components/search_engines/template_url_data.h"
#include "components/search_engines/template_url_service.h"
#include "content/public/browser/browser_message_filter.h"
......@@ -41,13 +43,17 @@ namespace {
class ContextMenuBrowserTest : public InProcessBrowserTest {
public:
ContextMenuBrowserTest() { }
ContextMenuBrowserTest() {}
TestRenderViewContextMenu* CreateContextMenu(GURL unfiltered_url, GURL url) {
TestRenderViewContextMenu* CreateContextMenu(
const GURL& unfiltered_url,
const GURL& url,
blink::WebContextMenuData::MediaType media_type) {
content::ContextMenuParams params;
params.media_type = blink::WebContextMenuData::MediaTypeNone;
params.media_type = media_type;
params.unfiltered_link_url = unfiltered_url;
params.link_url = url;
params.src_url = url;
WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
params.page_url = web_contents->GetController().GetActiveEntry()->GetURL();
......@@ -62,13 +68,19 @@ class ContextMenuBrowserTest : public InProcessBrowserTest {
menu->Init();
return menu;
}
TestRenderViewContextMenu* CreateContextMenuMediaTypeNone(
const GURL& unfiltered_url,
const GURL& url) {
return CreateContextMenu(unfiltered_url, url,
blink::WebContextMenuData::MediaTypeNone);
}
};
IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
OpenEntryPresentForNormalURLs) {
scoped_ptr<TestRenderViewContextMenu> menu(
CreateContextMenu(GURL("http://www.google.com/"),
GURL("http://www.google.com/")));
scoped_ptr<TestRenderViewContextMenu> menu(CreateContextMenuMediaTypeNone(
GURL("http://www.google.com/"), GURL("http://www.google.com/")));
ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
......@@ -78,8 +90,7 @@ IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
OpenEntryAbsentForFilteredURLs) {
scoped_ptr<TestRenderViewContextMenu> menu(
CreateContextMenu(GURL("chrome://history"),
GURL()));
CreateContextMenuMediaTypeNone(GURL("chrome://history"), GURL()));
ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWTAB));
ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENLINKNEWWINDOW));
......@@ -298,6 +309,44 @@ IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, ViewPageInfoWithNoEntry) {
menu.ExecuteCommand(IDC_CONTENT_CONTEXT_VIEWPAGEINFO, 0);
}
IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, DataSaverOpenOrigImageInNewTab) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendSwitch(
data_reduction_proxy::switches::kEnableDataReductionProxy);
scoped_ptr<TestRenderViewContextMenu> menu(
CreateContextMenu(GURL(), GURL("http://url.com/image.png"),
blink::WebContextMenuData::MediaTypeImage));
ASSERT_FALSE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB));
ASSERT_TRUE(menu->IsItemPresent(
IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB));
}
IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest,
DataSaverHttpsOpenImageInNewTab) {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendSwitch(
data_reduction_proxy::switches::kEnableDataReductionProxy);
scoped_ptr<TestRenderViewContextMenu> menu(
CreateContextMenu(GURL(), GURL("https://url.com/image.png"),
blink::WebContextMenuData::MediaTypeImage));
ASSERT_FALSE(
menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB));
ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB));
}
IN_PROC_BROWSER_TEST_F(ContextMenuBrowserTest, OpenImageInNewTab) {
scoped_ptr<TestRenderViewContextMenu> menu(
CreateContextMenu(GURL(), GURL("http://url.com/image.png"),
blink::WebContextMenuData::MediaTypeImage));
ASSERT_FALSE(
menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPEN_ORIGINAL_IMAGE_NEW_TAB));
ASSERT_TRUE(menu->IsItemPresent(IDC_CONTENT_CONTEXT_OPENIMAGENEWTAB));
}
class ThumbnailResponseWatcher : public content::NotificationObserver {
public:
enum QuitReason {
......
......@@ -47,6 +47,9 @@ bool IsEnabledOnCommandLine() {
namespace data_reduction_proxy {
const char kDataReductionPassThroughHeader[] =
"X-PSA-Client-Options: v=1,m=1\nCache-Control: no-cache";
DataReductionProxySettings::DataReductionProxySettings()
: unreachable_(false),
allowed_(false),
......@@ -110,10 +113,16 @@ void DataReductionProxySettings::SetOnDataReductionEnabledCallback(
on_data_reduction_proxy_enabled_.Run(IsDataReductionProxyEnabled());
}
bool DataReductionProxySettings::IsDataReductionProxyEnabled() {
bool DataReductionProxySettings::IsDataReductionProxyEnabled() const {
return spdy_proxy_auth_enabled_.GetValue() || IsEnabledOnCommandLine();
}
bool DataReductionProxySettings::CanUseDataReductionProxy(
const GURL& url) const {
return url.is_valid() && url.scheme() == url::kHttpScheme &&
IsDataReductionProxyEnabled();
}
bool
DataReductionProxySettings::IsDataReductionProxyAlternativeEnabled() const {
return data_reduction_proxy_alternative_enabled_.GetValue();
......
......@@ -29,6 +29,11 @@ class DataReductionProxyStatisticsPrefs;
// The number of days of bandwidth usage statistics that are tracked.
const unsigned int kNumDaysInHistory = 60;
// The header used to request a data reduction proxy pass through. When a
// request is sent to the data reduction proxy with this header, it will respond
// with the original uncompressed response.
extern const char kDataReductionPassThroughHeader[];
// The number of days of bandwidth usage statistics that are presented.
const unsigned int kNumDaysInHistorySummary = 30;
......@@ -74,7 +79,17 @@ class DataReductionProxySettings {
const base::Callback<void(bool)>& on_data_reduction_proxy_enabled);
// Returns true if the proxy is enabled.
bool IsDataReductionProxyEnabled();
bool IsDataReductionProxyEnabled() const;
// Returns true if the proxy can be used for the given url. This method does
// not take into account the proxy config or proxy retry list, so it can
// return true even when the proxy will not be used. Specifically, if
// another proxy configuration overrides use of data reduction proxy, or
// if data reduction proxy is in proxy retry list, then data reduction proxy
// will not be used, but this method will still return true. If this method
// returns false, then we are guaranteed that data reduction proxy will not be
// used.
bool CanUseDataReductionProxy(const GURL& url) const;
// Returns true if the alternative proxy is enabled.
bool IsDataReductionProxyAlternativeEnabled() const;
......@@ -186,7 +201,8 @@ class DataReductionProxySettings {
FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
TestIsProxyEnabledOrManaged);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
TestContentLengths);
TestCanUseDataReductionProxy);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest, TestContentLengths);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
TestGetDailyContentLengths);
FRIEND_TEST_ALL_PREFIXES(DataReductionProxySettingsTest,
......
......@@ -71,6 +71,23 @@ TEST_F(DataReductionProxySettingsTest, TestIsProxyEnabledOrManaged) {
test_context_->RunUntilIdle();
}
TEST_F(DataReductionProxySettingsTest, TestCanUseDataReductionProxy) {
settings_->InitPrefMembers();
// The proxy is disabled initially.
test_context_->config()->SetStateForTest(false, false, false, false);
GURL http_gurl("http://url.com/");
EXPECT_FALSE(settings_->CanUseDataReductionProxy(http_gurl));
CheckOnPrefChange(true, true, false);
EXPECT_TRUE(settings_->CanUseDataReductionProxy(http_gurl));
GURL https_gurl("https://url.com/");
EXPECT_FALSE(settings_->CanUseDataReductionProxy(https_gurl));
test_context_->RunUntilIdle();
}
TEST_F(DataReductionProxySettingsTest, TestResetDataReductionStatistics) {
int64 original_content_length;
int64 received_content_length;
......
......@@ -378,6 +378,15 @@ void RenderViewContextMenuBase::OpenURL(
const GURL& url, const GURL& referring_url,
WindowOpenDisposition disposition,
ui::PageTransition transition) {
OpenURLWithExtraHeaders(url, referring_url, disposition, transition, "");
}
void RenderViewContextMenuBase::OpenURLWithExtraHeaders(
const GURL& url,
const GURL& referring_url,
WindowOpenDisposition disposition,
ui::PageTransition transition,
const std::string& extra_headers) {
content::Referrer referrer = content::Referrer::SanitizeForRequest(
url,
content::Referrer(referring_url.GetAsReferrer(),
......@@ -386,8 +395,11 @@ void RenderViewContextMenuBase::OpenURL(
if (params_.link_url == url && disposition != OFF_THE_RECORD)
params_.custom_context.link_followed = url;
WebContents* new_contents = source_web_contents_->OpenURL(OpenURLParams(
url, referrer, disposition, transition, false));
OpenURLParams open_url_params(url, referrer, disposition, transition, false);
if (!extra_headers.empty())
open_url_params.extra_headers = extra_headers;
WebContents* new_contents = source_web_contents_->OpenURL(open_url_params);
if (!new_contents)
return;
......
......@@ -161,6 +161,13 @@ class RenderViewContextMenuBase : public ui::SimpleMenuModel::Delegate,
WindowOpenDisposition disposition,
ui::PageTransition transition);
// Opens the specified URL string in a new tab with the extra headers.
void OpenURLWithExtraHeaders(const GURL& url,
const GURL& referrer,
WindowOpenDisposition disposition,
ui::PageTransition transition,
const std::string& extra_headers);
content::ContextMenuParams params_;
content::WebContents* source_web_contents_;
// In the case of a MimeHandlerView this will point to the WebContents that
......
......@@ -57262,6 +57262,7 @@ To add a new entry, add it with any value and run test to compute valid value.
<int value="58" label="IDC_SPELLCHECK_SUGGESTION"/>
<int value="59" label="IDC_SPELLCHECK_ADD_TO_DICTIONARY"/>
<int value="60" label="IDC_SPELLPANEL_TOGGLE"/>
<int value="61" label="IDC_CONTENT_CONTEXT_OPENORIGINALIMAGENEWTAB"/>
</enum>
<enum name="ReportProcessingResult" type="int">
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment