blob: a87eb840694f345e613ed03754da3f65aa7208ee [file] [log] [blame]
// Copyright 2018 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.
#include "services/media_session/public/cpp/media_image_manager.h"
#include <algorithm>
#include "base/hash.h"
#include "ui/gfx/geometry/size.h"
namespace media_session {
namespace {
// The default score of unknown image size.
const double kDefaultImageSizeScore = 0.4;
// The scores for different image types. Keep them sorted by value.
const double kDefaultTypeScore = 0.6;
const double kPNGTypeScore = 1.0;
const double kJPEGTypeScore = 0.7;
const double kBMPTypeScore = 0.5;
const double kXIconTypeScore = 0.4;
const double kGIFTypeScore = 0.3;
double GetImageAspectRatioScore(const gfx::Size& size) {
double long_edge = std::max(size.width(), size.height());
double short_edge = std::min(size.width(), size.height());
return short_edge / long_edge;
}
std::string GetExtension(const std::string& path) {
auto const pos = path.find_last_of('.');
if (pos == std::string::npos)
return std::string();
return base::ToLowerASCII(path.substr(pos));
}
} // namespace
MediaImageManager::MediaImageManager(int min_size, int ideal_size)
: min_size_(min_size), ideal_size_(ideal_size) {}
MediaImageManager::~MediaImageManager() = default;
base::Optional<MediaMetadata::MediaImage> MediaImageManager::SelectImage(
const std::vector<MediaMetadata::MediaImage>& images) {
base::Optional<MediaMetadata::MediaImage> selected;
double best_score = 0;
for (auto& image : images) {
double score = GetImageScore(image);
if (score > best_score) {
best_score = score;
selected = image;
}
}
return selected;
}
double MediaImageManager::GetImageScore(
const MediaMetadata::MediaImage& image) const {
double best_size_score = 0;
if (image.sizes.empty()) {
best_size_score = kDefaultImageSizeScore;
} else {
for (auto& size : image.sizes)
best_size_score = std::max(best_size_score, GetImageSizeScore(size));
}
double type_score = kDefaultTypeScore;
if (base::Optional<double> ext_score = GetImageExtensionScore(image.src)) {
type_score = *ext_score;
} else if (base::Optional<double> mime_score =
GetImageTypeScore(image.type)) {
type_score = *mime_score;
}
return best_size_score * type_score;
}
double MediaImageManager::GetImageSizeScore(const gfx::Size& size) const {
return GetImageDominantSizeScore(size) * GetImageAspectRatioScore(size);
}
double MediaImageManager::GetImageDominantSizeScore(
const gfx::Size& size) const {
int dominant_size = std::max(size.width(), size.height());
// If the size is "any".
if (dominant_size == 0)
return 0.8;
// Ignore images that are too small.
if (dominant_size < min_size_)
return 0;
if (dominant_size <= ideal_size_)
return 0.8 * (dominant_size - min_size_) / (ideal_size_ - min_size_) + 0.2;
return 1.0 * ideal_size_ / dominant_size;
}
// static
base::Optional<double> MediaImageManager::GetImageExtensionScore(
const GURL& url) {
if (!url.has_path())
return base::nullopt;
std::string extension = GetExtension(url.path());
// These hashes are calculated in
// MediaImageManagerTest_CheckExpectedImageExtensionHashes
switch (base::PersistentHash(extension)) {
case 0x17f3f565: // .png
return kPNGTypeScore;
case 0x32937444: // .jpeg
return kJPEGTypeScore;
case 0x384e2a41: // .jpg
return kJPEGTypeScore;
case 0x9e9716f8: // .bmp
return kBMPTypeScore;
case 0xa123ca62: // .icon
return kXIconTypeScore;
case 0x97112590: // .gif
return kGIFTypeScore;
}
return base::nullopt;
}
// static
base::Optional<double> MediaImageManager::GetImageTypeScore(
const base::string16& type) {
// These hashes are calculated in
// MediaImageManagerTest_CheckExpectedImageTypeHashes
switch (
base::PersistentHash(type.data(), type.size() * sizeof(base::char16))) {
case 0xfd295465: // image/bmp
return kBMPTypeScore;
case 0xce81e113: // image/gif
return kGIFTypeScore;
case 0xb1b44900: // image/jpeg
return kJPEGTypeScore;
case 0x466b4956: // image/png
return kPNGTypeScore;
case 0x5668ffa3: // image/x-icon
return kXIconTypeScore;
}
return base::nullopt;
}
} // namespace media_session