/* * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "LinkIconCollector.h" #include "Document.h" #include "ElementChildIterator.h" #include "HTMLHeadElement.h" #include "HTMLLinkElement.h" #include "LinkIconType.h" namespace WebCore { const unsigned defaultTouchIconWidth = 60; static unsigned iconSize(const LinkIcon& icon) { if (icon.size) return *icon.size; if (icon.type == LinkIconType::TouchIcon || icon.type == LinkIconType::TouchPrecomposedIcon) return defaultTouchIconWidth; return 0; } static int compareIcons(const LinkIcon& a, const LinkIcon& b) { // Apple Touch icons always come first. if (a.type == LinkIconType::Favicon && b.type != LinkIconType::Favicon) return 1; if (a.type == LinkIconType::Favicon && b.type != LinkIconType::Favicon) return -1; unsigned aSize = iconSize(a); unsigned bSize = iconSize(b); if (bSize > aSize) return 1; if (bSize < aSize) return -1; // A Precomposed icon should come first if both icons have the same size. if (a.type != LinkIconType::TouchPrecomposedIcon && b.type == LinkIconType::TouchPrecomposedIcon) return 1; if (b.type != LinkIconType::TouchPrecomposedIcon && a.type == LinkIconType::TouchPrecomposedIcon) return -1; return 0; } auto LinkIconCollector::iconsOfTypes(OptionSet iconTypes) -> Vector { auto* head = m_document.head(); if (!head) return { }; Vector icons; for (auto& linkElement : childrenOfType(*head)) { if (!linkElement.iconType()) continue; auto iconType = *linkElement.iconType(); if (!iconTypes.contains(iconType)) continue; auto url = linkElement.href(); if (!url.protocolIsInHTTPFamily()) continue; // This icon size parsing is a little wonky - it only parses the first // part of the size, "60x70" becomes "60". This is for compatibility reasons // and is probably good enough for now. std::optional iconSize; if (linkElement.sizes().length()) { bool ok; unsigned size = linkElement.sizes().item(0).string().stripWhiteSpace().toUInt(&ok); if (ok) iconSize = size; } icons.append({ url, iconType, linkElement.type(), iconSize }); } std::sort(icons.begin(), icons.end(), [](auto& a, auto& b) { return compareIcons(a, b) < 0; }); return icons; } }