summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/modules/content_index/content_index_icon_loader.cc
blob: aa477aa0e6c3650b6060a85178da161e69e4a508 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// Copyright 2019 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 "third_party/blink/renderer/modules/content_index/content_index_icon_loader.h"

#include "base/barrier_closure.h"
#include "base/time/time.h"
#include "third_party/blink/public/common/manifest/manifest.h"
#include "third_party/blink/public/common/manifest/manifest_icon_selector.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/platform/web_icon_sizes_parser.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/loader/threaded_icon_loader.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"

namespace blink {

namespace {

constexpr base::TimeDelta kIconFetchTimeout = base::TimeDelta::FromSeconds(30);

void FetchIcon(ExecutionContext* execution_context,
               const KURL& icon_url,
               const gfx::Size& icon_size,
               ThreadedIconLoader::IconCallback callback) {
  ResourceRequest resource_request(icon_url);
  resource_request.SetRequestContext(mojom::RequestContextType::IMAGE);
  resource_request.SetRequestDestination(
      network::mojom::RequestDestination::kImage);
  resource_request.SetPriority(ResourceLoadPriority::kMedium);
  resource_request.SetTimeoutInterval(kIconFetchTimeout);

  auto* threaded_icon_loader = MakeGarbageCollected<ThreadedIconLoader>();
  threaded_icon_loader->Start(execution_context, resource_request, icon_size,
                              std::move(callback));
}

WebVector<Manifest::ImageResource> ToImageResource(
    ExecutionContext* execution_context,
    const Vector<mojom::blink::ContentIconDefinitionPtr>& icon_definitions) {
  WebVector<Manifest::ImageResource> image_resources;
  for (const auto& icon_definition : icon_definitions) {
    Manifest::ImageResource image_resource;
    image_resource.src = execution_context->CompleteURL(icon_definition->src);
    image_resource.type = WebString(icon_definition->type).Utf16();
    for (const auto& size :
         WebIconSizesParser::ParseIconSizes(icon_definition->sizes)) {
      image_resource.sizes.emplace_back(size);
    }
    if (image_resource.sizes.empty())
      image_resource.sizes.emplace_back(0, 0);
    image_resource.purpose.push_back(Manifest::ImageResource::Purpose::ANY);
    image_resources.emplace_back(std::move(image_resource));
  }
  return image_resources;
}

KURL FindBestIcon(WebVector<Manifest::ImageResource> image_resources,
                  const gfx::Size& icon_size) {
  return KURL(ManifestIconSelector::FindBestMatchingIcon(
      image_resources.ReleaseVector(),
      /* ideal_icon_height_in_px= */ icon_size.height(),
      /* minimum_icon_size_in_px= */ 0,
      /* max_width_to_height_ratio= */ icon_size.width() * 1.0f /
          icon_size.height(),
      Manifest::ImageResource::Purpose::ANY));
}

}  // namespace

ContentIndexIconLoader::ContentIndexIconLoader() = default;

void ContentIndexIconLoader::Start(
    ExecutionContext* execution_context,
    mojom::blink::ContentDescriptionPtr description,
    const Vector<gfx::Size>& icon_sizes,
    IconsCallback callback) {
  DCHECK(!description->icons.IsEmpty());
  DCHECK(!icon_sizes.IsEmpty());

  auto image_resources = ToImageResource(execution_context, description->icons);

  auto icons = std::make_unique<Vector<SkBitmap>>();
  icons->ReserveCapacity(icon_sizes.size());
  Vector<SkBitmap>* icons_ptr = icons.get();
  auto barrier_closure = base::BarrierClosure(
      icon_sizes.size(),
      WTF::Bind(&ContentIndexIconLoader::DidGetIcons, WrapPersistent(this),
                std::move(description), std::move(icons), std::move(callback)));

  for (const auto& icon_size : icon_sizes) {
    // TODO(crbug.com/973844): The same `src` may be chosen more than once.
    // This should probably only be downloaded once and resized.
    KURL icon_url = FindBestIcon(image_resources, icon_size);

    if (icon_url.IsEmpty())
      icon_url = KURL(image_resources[0].src);

    // |icons_ptr| is safe to use since it is owned by |barrier_closure|.
    FetchIcon(
        execution_context, icon_url, icon_size,
        WTF::Bind(
            [](base::OnceClosure done_closure, Vector<SkBitmap>* icons_ptr,
               SkBitmap icon, double resize_scale) {
              icons_ptr->push_back(std::move(icon));
              std::move(done_closure).Run();
            },
            barrier_closure, WTF::Unretained(icons_ptr)));
  }
}

void ContentIndexIconLoader::DidGetIcons(
    mojom::blink::ContentDescriptionPtr description,
    std::unique_ptr<Vector<SkBitmap>> icons,
    IconsCallback callback) {
  DCHECK(icons);
  std::move(callback).Run(std::move(description), std::move(*icons));
}

}  // namespace blink