IconController.cpp [plain text]
#include "config.h"
#include "IconController.h"
#include "Document.h"
#include "DocumentLoader.h"
#include "FrameLoader.h"
#include "FrameLoaderClient.h"
#include "IconDatabase.h"
#include "IconDatabaseBase.h"
#include "IconLoader.h"
#include "IconURL.h"
#include "Logging.h"
#include "MainFrame.h"
#include "Page.h"
#include "Settings.h"
#include <wtf/text/CString.h>
namespace WebCore {
IconController::IconController(Frame& frame)
: m_frame(frame)
, m_waitingForLoadDecision(false)
{
}
IconController::~IconController()
{
}
URL IconController::url()
{
IconURLs iconURLs = urlsForTypes(Favicon);
return iconURLs.isEmpty() ? URL() : iconURLs[0].m_iconURL;
}
IconURL IconController::iconURL(IconType iconType) const
{
IconURL result;
const Vector<IconURL>& iconURLs = m_frame.document()->iconURLs(iconType);
Vector<IconURL>::const_iterator iter(iconURLs.begin());
for (; iter != iconURLs.end(); ++iter) {
if (result.m_iconURL.isEmpty() || !iter->m_mimeType.isEmpty())
result = *iter;
}
return result;
}
IconURLs IconController::urlsForTypes(int iconTypesMask)
{
IconURLs iconURLs;
if (m_frame.tree().parent())
return iconURLs;
if (iconTypesMask & Favicon && !appendToIconURLs(Favicon, &iconURLs))
iconURLs.append(defaultURL(Favicon));
#if ENABLE(TOUCH_ICON_LOADING)
int missedIcons = 0;
if (iconTypesMask & TouchPrecomposedIcon)
missedIcons += appendToIconURLs(TouchPrecomposedIcon, &iconURLs) ? 0:1;
if (iconTypesMask & TouchIcon)
missedIcons += appendToIconURLs(TouchIcon, &iconURLs) ? 0:1;
if (missedIcons == 2) {
iconURLs.append(defaultURL(TouchPrecomposedIcon));
iconURLs.append(defaultURL(TouchIcon));
}
#endif
const Vector<IconURL>& allIconURLs = m_frame.document()->iconURLs(iconTypesMask);
for (Vector<IconURL>::const_iterator iter = allIconURLs.begin(); iter != allIconURLs.end(); ++iter) {
int i;
int iconCount = iconURLs.size();
for (i = 0; i < iconCount; ++i) {
if (*iter == iconURLs.at(i))
break;
}
if (i == iconCount)
iconURLs.append(*iter);
}
return iconURLs;
}
void IconController::commitToDatabase(const URL& icon)
{
LOG(IconDatabase, "Committing iconURL %s to database for pageURLs %s and %s", icon.string().ascii().data(), m_frame.document()->url().string().ascii().data(), m_frame.loader().initialRequest().url().string().ascii().data());
iconDatabase().setIconURLForPageURL(icon.string(), m_frame.document()->url().string());
iconDatabase().setIconURLForPageURL(icon.string(), m_frame.loader().initialRequest().url().string());
}
void IconController::startLoader()
{
if (!m_frame.isMainFrame())
return;
if (!iconDatabase().isEnabled())
return;
ASSERT(!m_frame.tree().parent());
if (!documentCanHaveIcon(m_frame.document()->url()))
return;
URL iconURL(url());
String urlString(iconURL.string());
if (urlString.isEmpty())
return;
if (!m_frame.settings().loadsImagesAutomatically() && !m_frame.settings().loadsSiteIconsIgnoringImageLoadingSetting())
return;
if (m_frame.loader().loadType() == FrameLoadType::Reload && m_frame.loader().loadType() == FrameLoadType::ReloadFromOrigin) {
continueLoadWithDecision(IconLoadYes);
return;
}
if (iconDatabase().supportsAsynchronousMode()) {
if (m_frame.page() && m_frame.page()->usesEphemeralSession())
return;
m_frame.loader().documentLoader()->getIconLoadDecisionForIconURL(urlString);
commitToDatabase(iconURL);
return;
}
IconLoadDecision decision = iconDatabase().synchronousLoadDecisionForIconURL(urlString, m_frame.loader().documentLoader());
if (decision == IconLoadUnknown) {
LOG(IconDatabase, "IconController %p might load icon %s later", this, urlString.ascii().data());
m_waitingForLoadDecision = true;
m_frame.loader().client().registerForIconNotification();
commitToDatabase(iconURL);
return;
}
continueLoadWithDecision(decision);
}
void IconController::stopLoader()
{
if (m_iconLoader)
m_iconLoader->stopLoading();
}
void IconController::loadDecisionReceived(IconLoadDecision iconLoadDecision)
{
if (!m_waitingForLoadDecision)
return;
LOG(IconDatabase, "IconController %p was told a load decision is available for its icon", this);
continueLoadWithDecision(iconLoadDecision);
m_waitingForLoadDecision = false;
}
void IconController::continueLoadWithDecision(IconLoadDecision iconLoadDecision)
{
ASSERT(iconLoadDecision != IconLoadUnknown);
if (iconLoadDecision == IconLoadNo) {
URL iconURL(url());
String urlString(iconURL.string());
if (urlString.isEmpty())
return;
LOG(IconDatabase, "IconController::startLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", urlString.ascii().data());
commitToDatabase(iconURL);
if (iconDatabase().supportsAsynchronousMode()) {
m_frame.loader().documentLoader()->getIconDataForIconURL(urlString);
return;
}
if (!iconDatabase().synchronousIconDataKnownForIconURL(urlString)) {
LOG(IconDatabase, "Told not to load icon %s but icon data is not yet available - registering for notification and requesting load from disk", urlString.ascii().data());
m_frame.loader().client().registerForIconNotification();
iconDatabase().synchronousIconForPageURL(m_frame.document()->url().string(), IntSize(0, 0));
iconDatabase().synchronousIconForPageURL(m_frame.loader().initialRequest().url().string(), IntSize(0, 0));
} else
m_frame.loader().client().dispatchDidReceiveIcon();
return;
}
if (!m_iconLoader)
m_iconLoader = std::make_unique<IconLoader>(m_frame);
m_iconLoader->startLoading();
}
bool IconController::appendToIconURLs(IconType iconType, IconURLs* iconURLs)
{
IconURL faviconURL = iconURL(iconType);
if (faviconURL.m_iconURL.isEmpty())
return false;
iconURLs->append(faviconURL);
return true;
}
IconURL IconController::defaultURL(IconType iconType)
{
URL documentURL = m_frame.document()->url();
if (!documentURL.protocolIsInHTTPFamily())
return IconURL();
URL url;
bool couldSetProtocol = url.setProtocol(documentURL.protocol());
ASSERT_UNUSED(couldSetProtocol, couldSetProtocol);
url.setHost(documentURL.host());
if (documentURL.hasPort())
url.setPort(documentURL.port());
if (iconType == Favicon) {
url.setPath("/favicon.ico");
return IconURL::defaultIconURL(url, Favicon);
}
#if ENABLE(TOUCH_ICON_LOADING)
if (iconType == TouchPrecomposedIcon) {
url.setPath("/apple-touch-icon-precomposed.png");
return IconURL::defaultIconURL(url, TouchPrecomposedIcon);
}
if (iconType == TouchIcon) {
url.setPath("/apple-touch-icon.png");
return IconURL::defaultIconURL(url, TouchIcon);
}
#endif
return IconURL();
}
}