summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorfinnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-13 21:52:32 +0000
committerfinnur@chromium.org <finnur@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-13 21:52:32 +0000
commit4604d1f4944206f24e864c71e29bc08b4d9500af (patch)
tree8dc2637b180b5c6e8a21b1984afb1a7bfa17c10b
parenta04f125f5fe5bbc56a3feaac4121a29452becedf (diff)
downloadchromium_src-4604d1f4944206f24e864c71e29bc08b4d9500af.zip
chromium_src-4604d1f4944206f24e864c71e29bc08b4d9500af.tar.gz
chromium_src-4604d1f4944206f24e864c71e29bc08b4d9500af.tar.bz2
RSS feed support (part 1), 2nd attempt.
Part 1 is RSS feed auto-discovery. This will parse the web page header to find the feeds in the document and notify the browser to display the RSS icon in the toolbar. You can click on the icon, but it will just navigate to the first feed on the page, which (unless it has been designed to be browser friendly) will just dump XML as text on the user. For this reason I have disabled the code that makes the RSS icon appear and intend to enable it when we have a good landing page to display the XML. Review URL: http://codereview.chromium.org/46055 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@11672 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/theme/rss.pngbin0 -> 943 bytes
-rw-r--r--chrome/app/theme/theme_resources.grd1
-rw-r--r--chrome/browser/browser.cc3
-rw-r--r--chrome/browser/cocoa/tab_contents_controller.mm1
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.cc4
-rw-r--r--chrome/browser/gtk/location_bar_view_gtk.h1
-rw-r--r--chrome/browser/location_bar.h3
-rw-r--r--chrome/browser/renderer_host/render_view_host.cc6
-rw-r--r--chrome/browser/renderer_host/render_view_host.h1
-rw-r--r--chrome/browser/renderer_host/render_view_host_delegate.h7
-rw-r--r--chrome/browser/tab_contents/navigation_entry.h10
-rw-r--r--chrome/browser/tab_contents/tab_contents.h9
-rw-r--r--chrome/browser/tab_contents/web_contents.cc24
-rw-r--r--chrome/browser/tab_contents/web_contents.h2
-rw-r--r--chrome/browser/toolbar_model.cc16
-rw-r--r--chrome/browser/toolbar_model.h4
-rw-r--r--chrome/browser/views/location_bar_view.cc218
-rw-r--r--chrome/browser/views/location_bar_view.h79
-rw-r--r--chrome/common/render_messages.h74
-rw-r--r--chrome/common/render_messages_internal.h3
-rw-r--r--chrome/renderer/render_view.cc10
-rw-r--r--chrome/renderer/render_view.h4
-rw-r--r--chrome/test/test_location_bar.h1
-rw-r--r--webkit/glue/feed.h46
-rw-r--r--webkit/glue/webframe.h5
-rw-r--r--webkit/glue/webframe_impl.cc63
-rw-r--r--webkit/glue/webframe_impl.h1
27 files changed, 516 insertions, 80 deletions
diff --git a/chrome/app/theme/rss.png b/chrome/app/theme/rss.png
new file mode 100644
index 0000000..58bda7f
--- /dev/null
+++ b/chrome/app/theme/rss.png
Binary files differ
diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd
index d6383db..c8dfa5e 100644
--- a/chrome/app/theme/theme_resources.grd
+++ b/chrome/app/theme/theme_resources.grd
@@ -57,6 +57,7 @@
<include name="IDR_RELOAD" file="reload.png" type="BINDATA" />
<include name="IDR_RELOAD_H" file="reload_h.png" type="BINDATA" />
<include name="IDR_RELOAD_P" file="reload_p.png" type="BINDATA" />
+ <include name="IDR_RSS_ICON" file="rss.png" type="BINDATA" />
<include name="IDR_STAR" file="star.png" type="BINDATA" />
<include name="IDR_STAR_D" file="star_d.png" type="BINDATA" />
<include name="IDR_STAR_H" file="star_h.png" type="BINDATA" />
diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc
index cbbe84d..452e94d 100644
--- a/chrome/browser/browser.cc
+++ b/chrome/browser/browser.cc
@@ -2243,6 +2243,9 @@ void Browser::ProcessPendingUIUpdates() {
updated_stuff[contents] |= TabContents::INVALIDATE_FAVICON;
}
+ if (flags & TabContents::INVALIDATE_FEEDLIST)
+ window()->GetLocationBar()->UpdateFeedIcon();
+
// Updating the URL happens synchronously in ScheduleUIUpdate.
if (flags & TabContents::INVALIDATE_LOAD && GetStatusBubble())
diff --git a/chrome/browser/cocoa/tab_contents_controller.mm b/chrome/browser/cocoa/tab_contents_controller.mm
index 331ec20..e0f7c10 100644
--- a/chrome/browser/cocoa/tab_contents_controller.mm
+++ b/chrome/browser/cocoa/tab_contents_controller.mm
@@ -64,6 +64,7 @@ class LocationBarBridge : public LocationBar {
virtual void AcceptInput() { NOTIMPLEMENTED(); }
virtual void FocusLocation();
virtual void FocusSearch() { NOTIMPLEMENTED(); }
+ virtual void UpdateFeedIcon() { NOTIMPLEMENTED(); }
virtual void SaveStateToContents(TabContents* contents) { NOTIMPLEMENTED(); }
private:
diff --git a/chrome/browser/gtk/location_bar_view_gtk.cc b/chrome/browser/gtk/location_bar_view_gtk.cc
index b8f18f8..4f6d623 100644
--- a/chrome/browser/gtk/location_bar_view_gtk.cc
+++ b/chrome/browser/gtk/location_bar_view_gtk.cc
@@ -165,6 +165,10 @@ void LocationBarViewGtk::FocusSearch() {
location_entry_->SetFocus();
}
+void LocationBarViewGtk::UpdateFeedIcon() {
+ NOTIMPLEMENTED();
+}
+
void LocationBarViewGtk::SaveStateToContents(TabContents* contents) {
NOTIMPLEMENTED();
}
diff --git a/chrome/browser/gtk/location_bar_view_gtk.h b/chrome/browser/gtk/location_bar_view_gtk.h
index d07091a..eb7bbf2 100644
--- a/chrome/browser/gtk/location_bar_view_gtk.h
+++ b/chrome/browser/gtk/location_bar_view_gtk.h
@@ -60,6 +60,7 @@ class LocationBarViewGtk : public AutocompleteEditController,
virtual void AcceptInput();
virtual void FocusLocation();
virtual void FocusSearch();
+ virtual void UpdateFeedIcon();
virtual void SaveStateToContents(TabContents* contents);
private:
diff --git a/chrome/browser/location_bar.h b/chrome/browser/location_bar.h
index 776427e..b6499d8 100644
--- a/chrome/browser/location_bar.h
+++ b/chrome/browser/location_bar.h
@@ -44,6 +44,9 @@ class LocationBar {
// focus to it.
virtual void FocusSearch() = 0;
+ // Update the state of the feed icon.
+ virtual void UpdateFeedIcon() = 0;
+
// Saves the state of the location bar to the specified TabContents, so that
// it can be restored later. (Done when switching tabs).
virtual void SaveStateToContents(TabContents* contents) = 0;
diff --git a/chrome/browser/renderer_host/render_view_host.cc b/chrome/browser/renderer_host/render_view_host.cc
index 734fd6d..8e2beec 100644
--- a/chrome/browser/renderer_host/render_view_host.cc
+++ b/chrome/browser/renderer_host/render_view_host.cc
@@ -761,6 +761,7 @@ void RenderViewHost::OnMessageReceived(const IPC::Message& msg) {
OnUnloadListenerChanged);
IPC_MESSAGE_HANDLER(ViewHostMsg_QueryFormFieldAutofill,
OnQueryFormFieldAutofill)
+ IPC_MESSAGE_HANDLER(ViewHostMsg_UpdateFeedList, OnMsgUpdateFeedList)
// Have the super handle all other messages.
IPC_MESSAGE_UNHANDLED(RenderWidgetHost::OnMessageReceived(msg))
IPC_END_MESSAGE_MAP_EX()
@@ -897,6 +898,11 @@ void RenderViewHost::OnMsgUpdateTitle(int32 page_id,
delegate_->UpdateTitle(this, page_id, title);
}
+void RenderViewHost::OnMsgUpdateFeedList(
+ const ViewHostMsg_UpdateFeedList_Params& params) {
+ delegate_->UpdateFeedList(this, params);
+}
+
void RenderViewHost::OnMsgUpdateEncoding(const std::wstring& encoding_name) {
delegate_->UpdateEncoding(this, encoding_name);
}
diff --git a/chrome/browser/renderer_host/render_view_host.h b/chrome/browser/renderer_host/render_view_host.h
index 62bdd64..a050a63 100644
--- a/chrome/browser/renderer_host/render_view_host.h
+++ b/chrome/browser/renderer_host/render_view_host.h
@@ -517,6 +517,7 @@ class RenderViewHost : public RenderWidgetHost {
void OnUpdateDragCursor(bool is_drop_target);
void OnTakeFocus(bool reverse);
void OnMsgPageHasOSDD(int32 page_id, const GURL& doc_url, bool autodetected);
+ void OnMsgUpdateFeedList(const ViewHostMsg_UpdateFeedList_Params& params);
void OnMsgInspectElementReply(int num_resources);
void DidPrintPage(const ViewHostMsg_DidPrintPage_Params& params);
void OnDebugMessage(const std::string& message);
diff --git a/chrome/browser/renderer_host/render_view_host_delegate.h b/chrome/browser/renderer_host/render_view_host_delegate.h
index db6623d..ebd9202 100644
--- a/chrome/browser/renderer_host/render_view_host_delegate.h
+++ b/chrome/browser/renderer_host/render_view_host_delegate.h
@@ -14,6 +14,7 @@
#include "base/logging.h"
#include "chrome/common/native_web_keyboard_event.h"
#include "net/base/load_states.h"
+#include "webkit/glue/feed.h"
#include "webkit/glue/password_form.h"
#include "webkit/glue/webpreferences.h"
#include "webkit/glue/window_open_disposition.h"
@@ -30,6 +31,7 @@ struct ThumbnailScore;
struct ContextMenuParams;
struct ViewHostMsg_DidPrintPage_Params;
struct ViewHostMsg_FrameNavigate_Params;
+struct ViewHostMsg_UpdateFeedList_Params;
struct WebDropData;
namespace base {
@@ -178,6 +180,11 @@ class RenderViewHostDelegate {
int32 page_id,
const std::wstring& title) { }
+ // The list of feeds have been updated.
+ virtual void UpdateFeedList(
+ RenderViewHost* render_view_host,
+ const ViewHostMsg_UpdateFeedList_Params& params) { }
+
// The page's encoding was changed and should be updated.
virtual void UpdateEncoding(RenderViewHost* render_view_host,
const std::wstring& encoding) { }
diff --git a/chrome/browser/tab_contents/navigation_entry.h b/chrome/browser/tab_contents/navigation_entry.h
index 55ed4f3..48e1750 100644
--- a/chrome/browser/tab_contents/navigation_entry.h
+++ b/chrome/browser/tab_contents/navigation_entry.h
@@ -15,6 +15,7 @@
#include "googleurl/src/gurl.h"
#include "grit/theme_resources.h"
#include "skia/include/SkBitmap.h"
+#include "webkit/glue/feed.h"
class NavigationController;
@@ -323,6 +324,14 @@ class NavigationEntry {
// if there is no navigation.
bool IsViewSourceMode() const;
+ // Feed accessor.
+ void set_feedlist(scoped_refptr<FeedList> feedlist) {
+ feedlist_ = feedlist;
+ }
+ scoped_refptr<FeedList> feedlist() {
+ return feedlist_;
+ }
+
// Tracking stuff ------------------------------------------------------------
// The transition type indicates what the user did to move to this page from
@@ -393,6 +402,7 @@ class NavigationEntry {
std::string content_state_;
int32 page_id_;
SSLStatus ssl_;
+ scoped_refptr<FeedList> feedlist_;
PageTransition::Type transition_type_;
GURL user_typed_url_;
bool has_post_data_;
diff --git a/chrome/browser/tab_contents/tab_contents.h b/chrome/browser/tab_contents/tab_contents.h
index 89b7430..b7a2cc9 100644
--- a/chrome/browser/tab_contents/tab_contents.h
+++ b/chrome/browser/tab_contents/tab_contents.h
@@ -74,10 +74,11 @@ class TabContents : public PageNavigator,
// Flags passed to the TabContentsDelegate.NavigationStateChanged to tell it
// what has changed. Combine them to update more than one thing.
enum InvalidateTypes {
- INVALIDATE_URL = 1, // The URL has changed.
- INVALIDATE_TITLE = 2, // The title has changed.
- INVALIDATE_FAVICON = 4, // The favicon has changed.
- INVALIDATE_LOAD = 8, // The loading state has changed
+ INVALIDATE_URL = 1, // The URL has changed.
+ INVALIDATE_TITLE = 2, // The title has changed.
+ INVALIDATE_FAVICON = 4, // The favicon has changed.
+ INVALIDATE_LOAD = 8, // The loading state has changed.
+ INVALIDATE_FEEDLIST = 16, // The Atom/RSS feed has changed.
// Helper for forcing a refresh.
INVALIDATE_EVERYTHING = 0xFFFFFFFF
diff --git a/chrome/browser/tab_contents/web_contents.cc b/chrome/browser/tab_contents/web_contents.cc
index 5b935b5..1e50600 100644
--- a/chrome/browser/tab_contents/web_contents.cc
+++ b/chrome/browser/tab_contents/web_contents.cc
@@ -42,6 +42,7 @@
#include "net/base/mime_util.h"
#include "net/base/net_errors.h"
#include "net/base/registry_controlled_domain.h"
+#include "webkit/glue/feed.h"
#include "webkit/glue/webkit_glue.h"
#if defined(OS_WIN)
@@ -807,6 +808,29 @@ void WebContents::UpdateTitle(RenderViewHost* rvh,
NotifyNavigationStateChanged(INVALIDATE_TITLE);
}
+void WebContents::UpdateFeedList(
+ RenderViewHost* rvh, const ViewHostMsg_UpdateFeedList_Params& params) {
+ if (!controller())
+ return;
+
+ // We might have an old RenderViewHost sending messages, and we should ignore
+ // those messages.
+ if (rvh != render_view_host())
+ return;
+
+ NavigationEntry* entry = controller()->GetEntryWithPageID(type(),
+ GetSiteInstance(),
+ params.page_id);
+ if (!entry)
+ return;
+
+ entry->set_feedlist(params.feedlist);
+
+ // Broadcast notifications when the UI should be updated.
+ if (entry == controller()->GetEntryAtOffset(0))
+ NotifyNavigationStateChanged(INVALIDATE_FEEDLIST);
+}
+
void WebContents::UpdateEncoding(RenderViewHost* render_view_host,
const std::wstring& encoding) {
set_encoding(encoding);
diff --git a/chrome/browser/tab_contents/web_contents.h b/chrome/browser/tab_contents/web_contents.h
index 5a07b5f..5ac7526 100644
--- a/chrome/browser/tab_contents/web_contents.h
+++ b/chrome/browser/tab_contents/web_contents.h
@@ -301,6 +301,8 @@ class WebContents : public TabContents,
virtual void UpdateTitle(RenderViewHost* render_view_host,
int32 page_id,
const std::wstring& title);
+ virtual void UpdateFeedList(RenderViewHost* render_view_host,
+ const ViewHostMsg_UpdateFeedList_Params& params);
virtual void UpdateEncoding(RenderViewHost* render_view_host,
const std::wstring& encoding);
virtual void UpdateTargetURL(int32 page_id, const GURL& url);
diff --git a/chrome/browser/toolbar_model.cc b/chrome/browser/toolbar_model.cc
index 93a224c..6661fb0 100644
--- a/chrome/browser/toolbar_model.cc
+++ b/chrome/browser/toolbar_model.cc
@@ -15,6 +15,7 @@
#include "chrome/common/pref_service.h"
#include "grit/generated_resources.h"
#include "net/base/net_util.h"
+#include "webkit/glue/feed.h"
ToolbarModel::ToolbarModel() : input_in_progress_(false) {
@@ -107,6 +108,21 @@ ToolbarModel::Icon ToolbarModel::GetIcon() {
}
}
+scoped_refptr<FeedList> ToolbarModel::GetFeedList() {
+ if (input_in_progress_)
+ return NULL;
+
+ NavigationController* navigation_controller = GetNavigationController();
+ if (!navigation_controller) // We might not have a controller on init.
+ return NULL;
+
+ NavigationEntry* entry = navigation_controller->GetActiveEntry();
+ if (!entry)
+ return NULL;
+
+ return entry->feedlist();
+}
+
void ToolbarModel::GetIconHoverText(std::wstring* text, SkColor* text_color) {
static const SkColor kOKHttpsInfoBubbleTextColor =
SkColorSetRGB(0, 153, 51); // Green.
diff --git a/chrome/browser/toolbar_model.h b/chrome/browser/toolbar_model.h
index daf3cea..3a6dff7 100644
--- a/chrome/browser/toolbar_model.h
+++ b/chrome/browser/toolbar_model.h
@@ -9,6 +9,7 @@
#include "base/basictypes.h"
#include "skia/include/SkColor.h"
+#include "webkit/glue/feed.h"
class NavigationController;
class NavigationEntry;
@@ -52,6 +53,9 @@ class ToolbarModel {
// Default value: NO_ICON.
virtual Icon GetIcon();
+ // Returns an array of available feeds.
+ virtual scoped_refptr<FeedList> GetFeedList();
+
// Sets the text and color of the text displayed in the info bubble that
// appears when the user hovers the mouse over the icon.
// Default value: empty string.
diff --git a/chrome/browser/views/location_bar_view.cc b/chrome/browser/views/location_bar_view.cc
index 0596974..d759fc0 100644
--- a/chrome/browser/views/location_bar_view.cc
+++ b/chrome/browser/views/location_bar_view.cc
@@ -91,6 +91,7 @@ LocationBarView::LocationBarView(Profile* profile,
keyword_hint_view_(profile),
type_to_search_view_(l10n_util::GetString(IDS_OMNIBOX_EMPTY_TEXT)),
security_image_view_(profile, model),
+ rss_image_view_(model),
popup_window_mode_(popup_window_mode),
first_run_bubble_(this) {
DCHECK(profile_);
@@ -153,6 +154,10 @@ void LocationBarView::Init() {
keyword_hint_view_.SetColor(gray);
keyword_hint_view_.SetParentOwned(false);
+ AddChildView(&rss_image_view_);
+ rss_image_view_.SetVisible(false);
+ rss_image_view_.SetParentOwned(false);
+
AddChildView(&security_image_view_);
security_image_view_.SetVisible(false);
security_image_view_.SetParentOwned(false);
@@ -174,6 +179,7 @@ void LocationBarView::Init() {
void LocationBarView::Update(const TabContents* tab_for_state_restoring) {
SetSecurityIcon(model_->GetIcon());
+ SetRssIconVisibility(model_->GetFeedList().get());
std::wstring info_text, info_tooltip;
SkColor text_color;
model_->GetInfoText(&info_text, &text_color, &info_tooltip);
@@ -183,6 +189,12 @@ void LocationBarView::Update(const TabContents* tab_for_state_restoring) {
SchedulePaint();
}
+void LocationBarView::UpdateFeedIcon() {
+ SetRssIconVisibility(model_->GetFeedList().get());
+ Layout();
+ SchedulePaint();
+}
+
void LocationBarView::Focus() {
::SetFocus(location_entry_->m_hWnd);
}
@@ -335,10 +347,16 @@ void LocationBarView::DoLayout(const bool force_layout) {
location_entry_->GetClientRect(&edit_bounds);
int entry_width = width() - (kEntryPadding * 2);
+
+ gfx::Size rss_image_size;
+ if (rss_image_view_.IsVisible()) {
+ rss_image_size = rss_image_view_.GetPreferredSize();
+ entry_width -= rss_image_size.width();
+ }
gfx::Size security_image_size;
if (security_image_view_.IsVisible()) {
security_image_size = security_image_view_.GetPreferredSize();
- entry_width -= security_image_size.width();
+ entry_width -= security_image_size.width() + kInnerPadding;
}
gfx::Size info_label_size;
if (info_label_.IsVisible()) {
@@ -365,9 +383,18 @@ void LocationBarView::DoLayout(const bool force_layout) {
location_y,
info_label_size.width(), location_height);
}
+ const int info_label_width = info_label_size.width() ?
+ info_label_size.width() + kInnerPadding : 0;
+ if (rss_image_view_.IsVisible()) {
+ rss_image_view_.SetBounds(width() - kEntryPadding -
+ info_label_width -
+ security_image_size.width() -
+ rss_image_size.width(),
+ location_y,
+ rss_image_size.width(),
+ location_height);
+ }
if (security_image_view_.IsVisible()) {
- const int info_label_width = info_label_size.width() ?
- info_label_size.width() + kInnerPadding : 0;
security_image_view_.SetBounds(width() - kEntryPadding - info_label_width -
security_image_size.width(), location_y, security_image_size.width(),
location_height);
@@ -498,6 +525,12 @@ void LocationBarView::SetSecurityIcon(ToolbarModel::Icon icon) {
}
}
+void LocationBarView::SetRssIconVisibility(FeedList* feeds) {
+ bool show_rss = feeds && feeds->list().size() > 0;
+ // TODO(finnur): Enable this when we have a good landing page to show feeds.
+ rss_image_view_.SetVisible(false);
+}
+
void LocationBarView::SetInfoText(const std::wstring& text,
SkColor text_color,
const std::wstring& tooltip_text) {
@@ -771,19 +804,20 @@ bool LocationBarView::ShouldLookupAccelerators(const views::KeyEvent& e) {
class LocationBarView::ShowInfoBubbleTask : public Task {
public:
- explicit ShowInfoBubbleTask(LocationBarView::SecurityImageView* image_view);
+ explicit ShowInfoBubbleTask(
+ LocationBarView::LocationBarImageView* image_view);
virtual void Run();
void Cancel();
private:
- LocationBarView::SecurityImageView* image_view_;
+ LocationBarView::LocationBarImageView* image_view_;
bool cancelled_;
DISALLOW_EVIL_CONSTRUCTORS(ShowInfoBubbleTask);
};
LocationBarView::ShowInfoBubbleTask::ShowInfoBubbleTask(
- LocationBarView::SecurityImageView* image_view)
+ LocationBarView::LocationBarImageView* image_view)
: cancelled_(false),
image_view_(image_view) {
}
@@ -842,27 +876,14 @@ void LocationBarView::ShowFirstRunBubbleInternal() {
bounds);
}
-// SecurityImageView------------------------------------------------------------
-
-// static
-SkBitmap* LocationBarView::SecurityImageView::lock_icon_ = NULL;
-SkBitmap* LocationBarView::SecurityImageView::warning_icon_ = NULL;
+// LocationBarImageView---------------------------------------------------------
-LocationBarView::SecurityImageView::SecurityImageView(Profile* profile,
- ToolbarModel* model)
- : profile_(profile),
- model_(model),
- show_info_bubble_task_(NULL),
- info_bubble_(NULL) {
- if (!lock_icon_) {
- ResourceBundle& rb = ResourceBundle::GetSharedInstance();
- lock_icon_ = rb.GetBitmapNamed(IDR_LOCK);
- warning_icon_ = rb.GetBitmapNamed(IDR_WARNING);
- }
- SetImageShown(LOCK);
+LocationBarView::LocationBarImageView::LocationBarImageView()
+ : show_info_bubble_task_(NULL),
+ info_bubble_(NULL) {
}
-LocationBarView::SecurityImageView::~SecurityImageView() {
+LocationBarView::LocationBarImageView::~LocationBarImageView() {
if (show_info_bubble_task_)
show_info_bubble_task_->Cancel();
@@ -873,25 +894,41 @@ LocationBarView::SecurityImageView::~SecurityImageView() {
}
}
-void LocationBarView::SecurityImageView::SetImageShown(Image image) {
- switch (image) {
- case LOCK:
- ImageView::SetImage(lock_icon_);
- break;
- case WARNING:
- ImageView::SetImage(warning_icon_);
- break;
- default:
- NOTREACHED();
- break;
+void LocationBarView::LocationBarImageView::OnMouseMoved(
+ const views::MouseEvent& event) {
+ if (show_info_bubble_task_) {
+ show_info_bubble_task_->Cancel();
+ show_info_bubble_task_ = NULL;
}
+
+ if (info_bubble_) {
+ // If an info bubble is currently showing, nothing to do.
+ return;
+ }
+
+ show_info_bubble_task_ = new ShowInfoBubbleTask(this);
+ MessageLoop::current()->PostDelayedTask(FROM_HERE, show_info_bubble_task_,
+ kInfoBubbleHoverDelayMs);
}
-void LocationBarView::SecurityImageView::ShowInfoBubble() {
- std::wstring text;
- SkColor text_color;
- model_->GetIconHoverText(&text, &text_color);
+void LocationBarView::LocationBarImageView::OnMouseExited(
+ const views::MouseEvent& event) {
+ if (show_info_bubble_task_) {
+ show_info_bubble_task_->Cancel();
+ show_info_bubble_task_ = NULL;
+ }
+
+ if (info_bubble_)
+ info_bubble_->Close();
+}
+
+void LocationBarView::LocationBarImageView::InfoBubbleClosing(
+ InfoBubble* info_bubble, bool closed_by_escape) {
+ info_bubble_ = NULL;
+}
+void LocationBarView::LocationBarImageView::ShowInfoBubbleImpl(
+ const std::wstring& text, SkColor text_color) {
gfx::Point location;
views::View::ConvertPointToScreen(this, &location);
gfx::Rect bounds(location.x(), location.y(), width(), height());
@@ -909,32 +946,40 @@ void LocationBarView::SecurityImageView::ShowInfoBubble() {
show_info_bubble_task_ = NULL;
}
-void LocationBarView::SecurityImageView::OnMouseMoved(
- const views::MouseEvent& event) {
- if (show_info_bubble_task_) {
- show_info_bubble_task_->Cancel();
- show_info_bubble_task_ = NULL;
- }
+// SecurityImageView------------------------------------------------------------
- if (info_bubble_) {
- // If an info bubble is currently showing, nothing to do.
- return;
+// static
+SkBitmap* LocationBarView::SecurityImageView::lock_icon_ = NULL;
+SkBitmap* LocationBarView::SecurityImageView::warning_icon_ = NULL;
+
+LocationBarView::SecurityImageView::SecurityImageView(Profile* profile,
+ ToolbarModel* model)
+ : LocationBarImageView(),
+ profile_(profile),
+ model_(model) {
+ if (!lock_icon_) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ lock_icon_ = rb.GetBitmapNamed(IDR_LOCK);
+ warning_icon_ = rb.GetBitmapNamed(IDR_WARNING);
}
+ SetImageShown(LOCK);
+}
- show_info_bubble_task_ = new ShowInfoBubbleTask(this);
- MessageLoop::current()->PostDelayedTask(FROM_HERE, show_info_bubble_task_,
- kInfoBubbleHoverDelayMs);
+LocationBarView::SecurityImageView::~SecurityImageView() {
}
-void LocationBarView::SecurityImageView::OnMouseExited(
- const views::MouseEvent& event) {
- if (show_info_bubble_task_) {
- show_info_bubble_task_->Cancel();
- show_info_bubble_task_ = NULL;
+void LocationBarView::SecurityImageView::SetImageShown(Image image) {
+ switch (image) {
+ case LOCK:
+ ImageView::SetImage(lock_icon_);
+ break;
+ case WARNING:
+ ImageView::SetImage(warning_icon_);
+ break;
+ default:
+ NOTREACHED();
+ break;
}
-
- if (info_bubble_)
- info_bubble_->Close();
}
bool LocationBarView::SecurityImageView::OnMousePressed(
@@ -953,10 +998,57 @@ bool LocationBarView::SecurityImageView::OnMousePressed(
return true;
}
-void LocationBarView::SecurityImageView::InfoBubbleClosing(
- InfoBubble* info_bubble,
- bool closed_by_escape) {
- info_bubble_ = NULL;
+void LocationBarView::SecurityImageView::ShowInfoBubble() {
+ std::wstring text;
+ SkColor text_color;
+ model_->GetIconHoverText(&text, &text_color);
+
+ ShowInfoBubbleImpl(text, text_color);
+}
+
+// RssImageView------------------------------------------------------------
+
+// static
+SkBitmap* LocationBarView::RssImageView::rss_icon_ = NULL;
+
+LocationBarView::RssImageView::RssImageView(ToolbarModel* model)
+ : model_(model),
+ LocationBarImageView() {
+ if (!rss_icon_) {
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ rss_icon_ = rb.GetBitmapNamed(IDR_RSS_ICON);
+ }
+ ImageView::SetImage(rss_icon_);
+}
+
+LocationBarView::RssImageView::~RssImageView() {
+}
+
+bool LocationBarView::RssImageView::OnMousePressed(
+ const views::MouseEvent& event) {
+ NavigationEntry* entry =
+ BrowserList::GetLastActive()->GetSelectedTabContents()->
+ controller()->GetActiveEntry();
+ if (!entry) {
+ NOTREACHED();
+ return true;
+ }
+
+ // Navigate to the first item in the feed list.
+ scoped_refptr<FeedList> feeds = model_->GetFeedList();
+ DCHECK(feeds.get() && feeds->list().size() > 0);
+
+ // TODO(finnur): Make this do more than just display the XML in the browser.
+ BrowserList::GetLastActive()->OpenURL(feeds->list()[0].url, GURL(),
+ CURRENT_TAB, PageTransition::LINK);
+ return true;
+}
+
+void LocationBarView::RssImageView::ShowInfoBubble() {
+ // TODO(finnur): Get this string from the resources.
+ std::wstring text = L"Subscribe to this feed";
+ SkColor text_color = SK_ColorBLUE;
+ ShowInfoBubbleImpl(text, text_color);
}
bool LocationBarView::OverrideAccelerator(
diff --git a/chrome/browser/views/location_bar_view.h b/chrome/browser/views/location_bar_view.h
index 07b9e06..99822f4 100644
--- a/chrome/browser/views/location_bar_view.h
+++ b/chrome/browser/views/location_bar_view.h
@@ -120,6 +120,7 @@ class LocationBarView : public LocationBar,
virtual void AcceptInput();
virtual void FocusLocation();
virtual void FocusSearch();
+ virtual void UpdateFeedIcon();
virtual void SaveStateToContents(TabContents* contents);
static const int kVertMargin;
@@ -224,13 +225,45 @@ class LocationBarView : public LocationBar,
class ShowInfoBubbleTask;
class ShowFirstRunBubbleTask;
+ class LocationBarImageView : public views::ImageView,
+ public InfoBubbleDelegate {
+ public:
+ LocationBarImageView();
+ virtual ~LocationBarImageView();
+
+ // Overridden from view for the mouse hovering.
+ virtual void OnMouseMoved(const views::MouseEvent& event);
+ virtual void OnMouseExited(const views::MouseEvent& event);
+ virtual bool OnMousePressed(const views::MouseEvent& event) = 0;
+
+ // InfoBubbleDelegate
+ void InfoBubbleClosing(InfoBubble* info_bubble, bool closed_by_escape);
+ bool CloseOnEscape() { return true; }
+
+ virtual void ShowInfoBubble() = 0;
+
+ protected:
+ void ShowInfoBubbleImpl(const std::wstring& text, SkColor text_color);
+
+ private:
+ friend class ShowInfoBubbleTask;
+
+ // The currently shown info bubble if any.
+ InfoBubble* info_bubble_;
+
+ // A task used to display the info bubble when the mouse hovers on the
+ // image.
+ ShowInfoBubbleTask* show_info_bubble_task_;
+
+ DISALLOW_COPY_AND_ASSIGN(LocationBarImageView);
+ };
+
// SecurityImageView is used to display the lock or warning icon when the
// current URL's scheme is https.
//
// If a message has been set with SetInfoBubbleText, it displays an info
// bubble when the mouse hovers on the image.
- class SecurityImageView : public views::ImageView,
- public InfoBubbleDelegate {
+ class SecurityImageView : public LocationBarImageView {
public:
enum Image {
LOCK = 0,
@@ -244,21 +277,13 @@ class LocationBarView : public LocationBar,
void SetImageShown(Image image);
// Overridden from view for the mouse hovering.
- virtual void OnMouseMoved(const views::MouseEvent& event);
- virtual void OnMouseExited(const views::MouseEvent& event);
virtual bool OnMousePressed(const views::MouseEvent& event);
- // InfoBubbleDelegate
- void InfoBubbleClosing(InfoBubble* info_bubble, bool closed_by_escape);
- bool CloseOnEscape() { return true; }
-
void set_profile(Profile* profile) { profile_ = profile; }
- private:
- friend class ShowInfoBubbleTask;
-
- void ShowInfoBubble();
+ virtual void ShowInfoBubble();
+ private:
// The lock icon shown when using HTTPS.
static SkBitmap* lock_icon_;
@@ -279,6 +304,30 @@ class LocationBarView : public LocationBar,
DISALLOW_EVIL_CONSTRUCTORS(SecurityImageView);
};
+ // RssImageView is used to display the RSS icon when the page has a feed that
+ // you can subscribe to.
+ //
+ // If a message has been set with SetInfoBubbleText, it displays an info
+ // bubble when the mouse hovers on the image.
+ class RssImageView : public LocationBarImageView {
+ public:
+ explicit RssImageView(ToolbarModel* model);
+ virtual ~RssImageView();
+
+ // Overridden from view for the mouse hovering.
+ virtual bool OnMousePressed(const views::MouseEvent& event);
+
+ virtual void ShowInfoBubble();
+
+ private:
+ // The RSS icon shown when page has a feed.
+ static SkBitmap* rss_icon_;
+
+ ToolbarModel* model_;
+
+ DISALLOW_COPY_AND_ASSIGN(RssImageView);
+ };
+
// Both Layout and OnChanged call into this. This updates the contents
// of the 3 views: selected_keyword, keyword_hint and type_search_view. If
// force_layout is true, or one of these views has changed in such a way as
@@ -316,6 +365,9 @@ class LocationBarView : public LocationBar,
// Sets the security icon to display. Note that no repaint is done.
void SetSecurityIcon(ToolbarModel::Icon icon);
+ // Sets the RSS icon visibility.
+ void SetRssIconVisibility(FeedList* feeds);
+
// Sets the text that should be displayed in the info label and its associated
// tooltip text. Call with an empty string if the info label should be
// hidden.
@@ -381,6 +433,9 @@ class LocationBarView : public LocationBar,
// The view that shows the lock/warning when in HTTPS mode.
SecurityImageView security_image_view_;
+ // The view that shows the RSS icon when the page has an RSS feed.
+ RssImageView rss_image_view_;
+
// A label displayed after the lock icon to show some extra information.
views::Label info_label_;
diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h
index 048a0a6..ded088f 100644
--- a/chrome/common/render_messages.h
+++ b/chrome/common/render_messages.h
@@ -28,6 +28,7 @@
#include "webkit/glue/autofill_form.h"
#include "webkit/glue/cache_manager.h"
#include "webkit/glue/context_menu.h"
+#include "webkit/glue/feed.h"
#include "webkit/glue/form_data.h"
#include "webkit/glue/password_form.h"
#include "webkit/glue/password_form_dom_manager.h"
@@ -43,6 +44,17 @@
#include "skia/include/SkBitmap.h"
#endif
+struct ViewHostMsg_UpdateFeedList_Params {
+ // The page_id for this navigation, or -1 if it is a new navigation. Back,
+ // Forward, and Reload navigations should have a valid page_id. If the load
+ // succeeds, then this page_id will be reflected in the resulting
+ // ViewHostMsg_FrameNavigate message.
+ int32 page_id;
+
+ // The list of available feeds.
+ scoped_refptr<FeedList> feedlist;
+};
+
// Parameters structure for ViewMsg_Navigate, which has too many data
// parameters to be reasonably put in a predefined IPC message.
struct ViewMsg_Navigate_Params {
@@ -516,6 +528,67 @@ struct ParamTraits<WebInputEvent::Type> {
}
};
+// Traits for ViewHostMsg_UpdateFeedList_Params structure to pack/unpack.
+template <>
+struct ParamTraits<ViewHostMsg_UpdateFeedList_Params> {
+ typedef ViewHostMsg_UpdateFeedList_Params param_type;
+ static void Write(Message* msg, const param_type& param) {
+ WriteParam(msg, param.page_id);
+ WriteParam(msg, param.feedlist->list().size());
+ for (std::vector<FeedItem>::const_iterator iter =
+ param.feedlist->list().begin();
+ iter != param.feedlist->list().end(); iter++) {
+ WriteParam(msg, iter->title);
+ WriteParam(msg, iter->type);
+ WriteParam(msg, iter->url);
+ }
+ }
+ static bool Read(const Message* msg, void** iter, param_type* param) {
+ param->feedlist = new FeedList();
+ if (!ReadParam(msg, iter, &param->page_id))
+ return false;
+
+ size_t arraysize = 0;
+ if (!ReadParam(msg, iter, &arraysize))
+ return false;
+
+ if (arraysize > FeedList::kMaxFeeds) {
+ NOTREACHED() << L"Too many feeds sent by the renderer";
+ return false;
+ }
+
+ bool ret = true;
+ for (size_t i = 0; i < arraysize; i++) {
+ FeedItem feeditem;
+ ret = ReadParam(msg, iter, &feeditem.title) &&
+ ReadParam(msg, iter, &feeditem.type) &&
+ ReadParam(msg, iter, &feeditem.url);
+ if (!ret)
+ return ret;
+ param->feedlist->Add(feeditem);
+ }
+
+ return ret;
+ }
+ static void Log(const param_type& param, std::wstring* log) {
+ log->append(L"(");
+ LogParam(param.page_id, log);
+ log->append(L", {");
+ for (std::vector<FeedItem>::const_iterator iter =
+ param.feedlist->list().begin();
+ iter != param.feedlist->list().end(); iter++) {
+ log->append(L"[");
+ LogParam(iter->title, log);
+ log->append(L", ");
+ LogParam(iter->type, log);
+ log->append(L", ");
+ LogParam(iter->url, log);
+ log->append(L"]");
+ }
+ log->append(L"})");
+ }
+};
+
template <>
struct ParamTraits<AccessibilityInParams> {
typedef AccessibilityInParams param_type;
@@ -724,7 +797,6 @@ struct ParamTraits<AutofillForm> {
result = result && ReadParam(m, iter, &elements_size);
p->elements.resize(elements_size);
for (size_t i = 0; i < elements_size; i++) {
- std::wstring s;
result = result && ReadParam(m, iter, &(p->elements[i].name));
result = result && ReadParam(m, iter, &(p->elements[i].value));
}
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index 5ebe6e9..eb6dc2b6 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -1220,4 +1220,7 @@ IPC_BEGIN_MESSAGES(ViewHost)
IPC_MESSAGE_CONTROL1(ViewHostMsg_ForwardToWorker,
IPC::Message /* message */)
+ // Notification when new feeds have been discovered on the page.
+ IPC_MESSAGE_ROUTED1(ViewHostMsg_UpdateFeedList,
+ ViewHostMsg_UpdateFeedList_Params)
IPC_END_MESSAGES(ViewHost)
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index 8af74f5..8e7a45e 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -1219,6 +1219,9 @@ void RenderView::DidStopLoading(WebView* webview) {
if (!favicon_url.is_empty())
Send(new ViewHostMsg_UpdateFavIconURL(routing_id_, page_id_, favicon_url));
+ // Update the list of available feeds.
+ UpdateFeedList(webview->GetMainFrame()->GetFeedList());
+
AddGURLSearchProvider(webview->GetMainFrame()->GetOSDDURL(),
true); // autodetected
@@ -1696,6 +1699,13 @@ void RenderView::AddGURLSearchProvider(const GURL& osd_url, bool autodetected) {
autodetected));
}
+void RenderView::UpdateFeedList(scoped_refptr<FeedList> feedlist) {
+ ViewHostMsg_UpdateFeedList_Params params;
+ params.page_id = page_id_;
+ params.feedlist = feedlist;
+ Send(new ViewHostMsg_UpdateFeedList(routing_id_, params));
+}
+
bool RenderView::RunBeforeUnloadConfirm(WebFrame* webframe,
const std::wstring& message) {
bool success = false;
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index 29c262d7..8973346 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -29,6 +29,7 @@
#include "testing/gtest/include/gtest/gtest_prod.h"
#include "webkit/glue/console_message_level.h"
#include "webkit/glue/dom_serializer_delegate.h"
+#include "webkit/glue/feed.h"
#include "webkit/glue/form_data.h"
#include "webkit/glue/password_form_dom_manager.h"
#include "webkit/glue/webview_delegate.h"
@@ -431,6 +432,9 @@ class RenderView : public RenderWidget,
// keyword search.
void AddGURLSearchProvider(const GURL& osd_url, bool autodetected);
+ // Update the feed list.
+ void UpdateFeedList(scoped_refptr<FeedList> feedlist);
+
// Tells the browser process to navigate to a back/forward entry at the given
// offset from current.
void GoToEntryAtOffset(int offset);
diff --git a/chrome/test/test_location_bar.h b/chrome/test/test_location_bar.h
index d81eb4a..b303a737 100644
--- a/chrome/test/test_location_bar.h
+++ b/chrome/test/test_location_bar.h
@@ -36,6 +36,7 @@ class TestLocationBar : public LocationBar {
virtual void AcceptInput() {}
virtual void FocusLocation() {}
virtual void FocusSearch() {}
+ virtual void UpdateFeedIcon() {}
virtual void SaveStateToContents(TabContents* contents) {}
private:
diff --git a/webkit/glue/feed.h b/webkit/glue/feed.h
new file mode 100644
index 0000000..e475c4a
--- /dev/null
+++ b/webkit/glue/feed.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2009 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 CHROME_COMMON_FEED_H_
+#define CHROME_COMMON_FEED_H_
+
+#include <string>
+#include <vector>
+
+#include "base/ref_counted.h"
+#include "googleurl/src/gurl.h"
+
+struct FeedItem {
+ // The feed title.
+ std::wstring title;
+ // The feed type, for example: "application/rss+xml". The type can be blank.
+ std::wstring type;
+ // The URL to subscribe to the feed.
+ GURL url;
+};
+
+class FeedList : public base::RefCounted<FeedList> {
+ public:
+ // We limit the number of feeds that can be sent so that a rouge renderer
+ // doesn't cause excessive memory usage in the browser process by specifying
+ // a huge number of RSS feeds for the browser to parse.
+ static const size_t kMaxFeeds = 50;
+
+ FeedList() {}
+
+ void Add(const FeedItem &item) {
+ list_.push_back(item);
+ }
+
+ const std::vector<FeedItem>& list() const {
+ return list_;
+ }
+
+ private:
+ std::vector<FeedItem> list_;
+
+ DISALLOW_COPY_AND_ASSIGN(FeedList);
+};
+
+#endif // CHROME_COMMON_FEED_H_
diff --git a/webkit/glue/webframe.h b/webkit/glue/webframe.h
index d35376e..571b281 100644
--- a/webkit/glue/webframe.h
+++ b/webkit/glue/webframe.h
@@ -9,6 +9,7 @@
#include "skia/ext/bitmap_platform_device.h"
#include "skia/ext/platform_canvas.h"
#include "webkit/glue/console_message_level.h"
+#include "webkit/glue/feed.h"
#include "webkit/glue/find_in_page_request.h"
class GURL;
@@ -129,6 +130,10 @@ class WebFrame {
// the page does not have a valid document, an empty GURL is returned.
virtual GURL GetOSDDURL() const = 0;
+ // Return the list of feeds specified in the document for the frame. If
+ // the page does not have a valid document, an empty list is returned.
+ virtual scoped_refptr<class FeedList> GetFeedList() const = 0;
+
// Returns the committed data source, which is the last data source that has
// successfully started loading. Will return NULL if no provisional data
// has been committed.
diff --git a/webkit/glue/webframe_impl.cc b/webkit/glue/webframe_impl.cc
index 4f71ec3..62b27a8 100644
--- a/webkit/glue/webframe_impl.cc
+++ b/webkit/glue/webframe_impl.cc
@@ -135,6 +135,7 @@ MSVC_POP_WARNING();
#include "webkit/glue/alt_error_page_resource_fetcher.h"
#include "webkit/glue/dom_operations.h"
#include "webkit/glue/dom_operations_private.h"
+#include "webkit/glue/feed.h"
#include "webkit/glue/glue_serialize.h"
#include "webkit/glue/glue_util.h"
#include "webkit/glue/webdatasource_impl.h"
@@ -485,6 +486,68 @@ GURL WebFrameImpl::GetOSDDURL() const {
return GURL();
}
+scoped_refptr<FeedList> WebFrameImpl::GetFeedList() const {
+ scoped_refptr<FeedList> feedlist = new FeedList();
+
+ WebCore::FrameLoader* frame_loader = frame_->loader();
+ if (frame_loader->state() != WebCore::FrameStateComplete ||
+ !frame_->document() ||
+ !frame_->document()->head() ||
+ frame_->tree()->parent())
+ return feedlist;
+
+ // We only consider HTML documents with <head> tags.
+ // (Interestingly, isHTMLDocument() returns false for some pages --
+ // perhaps an XHTML thing? It doesn't really matter because head() is
+ // a method on Documents anyway.)
+ WebCore::HTMLHeadElement* head = frame_->document()->head();
+ if (!head)
+ return feedlist;
+
+ // Iterate through all children of the <head>, looking for feed links.
+ for (WebCore::Node* node = head->firstChild();
+ node; node = node->nextSibling()) {
+ // Skip over all nodes except <link ...>.
+ if (!node->isHTMLElement())
+ continue;
+ if (!static_cast<WebCore::Element*>(node)->hasLocalName("link"))
+ continue;
+
+ const WebCore::HTMLLinkElement* link =
+ static_cast<WebCore::HTMLLinkElement*>(node);
+
+ // Look at the 'rel' tag and see if we have a feed.
+ std::wstring rel = webkit_glue::StringToStdWString(link->rel());
+ bool is_feed = false;
+ if (LowerCaseEqualsASCII(rel, "feed") ||
+ LowerCaseEqualsASCII(rel, "feed alternate")) {
+ // rel="feed" or rel="alternate feed" always means this is a feed.
+ is_feed = true;
+ } else if (LowerCaseEqualsASCII(rel, "alternate")) {
+ // Otherwise, rel="alternate" may mean a feed if it has a certain mime
+ // type.
+ std::wstring link_type = webkit_glue::StringToStdWString(link->type());
+ TrimWhitespace(link_type, TRIM_ALL, &link_type);
+ if (LowerCaseEqualsASCII(link_type, "application/atom+xml") ||
+ LowerCaseEqualsASCII(link_type, "application/rss+xml")) {
+ is_feed = true;
+ }
+ }
+
+ if (is_feed) {
+ FeedItem feedItem;
+ feedItem.title = webkit_glue::StringToStdWString(link->title());
+ TrimWhitespace(feedItem.title, TRIM_ALL, &feedItem.title);
+ feedItem.type = webkit_glue::StringToStdWString(link->type());
+ TrimWhitespace(feedItem.type, TRIM_ALL, &feedItem.type);
+ feedItem.url = webkit_glue::KURLToGURL(link->href());
+ feedlist->Add(feedItem);
+ }
+ }
+
+ return feedlist;
+}
+
bool WebFrameImpl::GetPreviousHistoryState(std::string* history_state) const {
// We use the previous item here because documentState (filled-out forms)
// only get saved to history when it becomes the previous item. The caller
diff --git a/webkit/glue/webframe_impl.h b/webkit/glue/webframe_impl.h
index ed7ee15..e49802f 100644
--- a/webkit/glue/webframe_impl.h
+++ b/webkit/glue/webframe_impl.h
@@ -99,6 +99,7 @@ class WebFrameImpl : public WebFrame, public base::RefCounted<WebFrameImpl> {
virtual GURL GetURL() const;
virtual GURL GetFavIconURL() const;
virtual GURL GetOSDDURL() const;
+ virtual scoped_refptr<class FeedList> GetFeedList() const;
virtual WebDataSource* GetDataSource() const;
virtual WebDataSource* GetProvisionalDataSource() const;
virtual void StopLoading();