Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14828863
D19209.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
32 KB
Referenced Files
None
Subscribers
None
D19209.diff
View Options
diff --git a/webroot/rsrc/favicons/apple-touch-icon-120x120.png b/resources/builtin/favicon/default-120x120.png
rename from webroot/rsrc/favicons/apple-touch-icon-120x120.png
rename to resources/builtin/favicon/default-120x120.png
diff --git a/webroot/rsrc/favicons/favicon-128.png b/resources/builtin/favicon/default-128x128.png
rename from webroot/rsrc/favicons/favicon-128.png
rename to resources/builtin/favicon/default-128x128.png
diff --git a/webroot/rsrc/favicons/apple-touch-icon-152x152.png b/resources/builtin/favicon/default-152x152.png
rename from webroot/rsrc/favicons/apple-touch-icon-152x152.png
rename to resources/builtin/favicon/default-152x152.png
diff --git a/webroot/rsrc/favicons/apple-touch-icon-76x76.png b/resources/builtin/favicon/default-76x76.png
rename from webroot/rsrc/favicons/apple-touch-icon-76x76.png
rename to resources/builtin/favicon/default-76x76.png
diff --git a/resources/builtin/favicon/dot-pink-64x64.png b/resources/builtin/favicon/dot-pink-64x64.png
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/resources/builtin/favicon/dot-red-64x64.png b/resources/builtin/favicon/dot-red-64x64.png
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -16,7 +16,6 @@
'differential.pkg.js' => 'f6d809c0',
'diffusion.pkg.css' => 'a2d17c7d',
'diffusion.pkg.js' => '6134c5a1',
- 'favicon.ico' => '30672e08',
'maniphest.pkg.css' => '4845691a',
'maniphest.pkg.js' => '4d7e79c8',
'rsrc/audio/basic/alert.mp3' => '98461568',
@@ -270,28 +269,8 @@
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadPreloadedSource.js' => '54f314a0',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadSource.js' => 'ab9e0a82',
'rsrc/externals/javelin/lib/control/typeahead/source/TypeaheadStaticSource.js' => '6c0e62fa',
- 'rsrc/favicons/apple-touch-icon-114x114.png' => '12a24178',
- 'rsrc/favicons/apple-touch-icon-120x120.png' => '0d1543c7',
- 'rsrc/favicons/apple-touch-icon-144x144.png' => '8043b5a5',
- 'rsrc/favicons/apple-touch-icon-152x152.png' => '65905ecd',
- 'rsrc/favicons/apple-touch-icon-57x57.png' => '2bfc7b0a',
- 'rsrc/favicons/apple-touch-icon-60x60.png' => '8ff52925',
- 'rsrc/favicons/apple-touch-icon-72x72.png' => 'a2bb65d6',
- 'rsrc/favicons/apple-touch-icon-76x76.png' => '2d061a11',
- 'rsrc/favicons/favicon-128.png' => '72f7e812',
'rsrc/favicons/favicon-16x16.png' => 'fc6275ba',
- 'rsrc/favicons/favicon-196x196.png' => '95db275e',
- 'rsrc/favicons/favicon-32x32.png' => '5bd18b6c',
- 'rsrc/favicons/favicon-96x96.png' => '7242c8e9',
- 'rsrc/favicons/favicon-mention.ico' => '1fdd0fa4',
- 'rsrc/favicons/favicon-message.ico' => '115bc010',
- 'rsrc/favicons/favicon.ico' => 'cdb11121',
'rsrc/favicons/mask-icon.svg' => 'e132a80f',
- 'rsrc/favicons/mstile-144x144.png' => '310c2ee5',
- 'rsrc/favicons/mstile-150x150.png' => '74bf5133',
- 'rsrc/favicons/mstile-310x150.png' => '4a49d3ee',
- 'rsrc/favicons/mstile-310x310.png' => 'a52ab264',
- 'rsrc/favicons/mstile-70x70.png' => '5edce7b8',
'rsrc/image/BFCFDA.png' => 'd5ec91f4',
'rsrc/image/actions/edit.png' => '2fc41442',
'rsrc/image/avatar.png' => '17d346a4',
diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2953,6 +2953,8 @@
'PhabricatorFactObjectDimension' => 'applications/fact/storage/PhabricatorFactObjectDimension.php',
'PhabricatorFactRaw' => 'applications/fact/storage/PhabricatorFactRaw.php',
'PhabricatorFactUpdateIterator' => 'applications/fact/extract/PhabricatorFactUpdateIterator.php',
+ 'PhabricatorFaviconRef' => 'applications/files/favicon/PhabricatorFaviconRef.php',
+ 'PhabricatorFaviconRefQuery' => 'applications/files/favicon/PhabricatorFaviconRefQuery.php',
'PhabricatorFavoritesApplication' => 'applications/favorites/application/PhabricatorFavoritesApplication.php',
'PhabricatorFavoritesController' => 'applications/favorites/controller/PhabricatorFavoritesController.php',
'PhabricatorFavoritesMainMenuBarExtension' => 'applications/favorites/engineextension/PhabricatorFavoritesMainMenuBarExtension.php',
@@ -4331,7 +4333,6 @@
'PhabricatorSystemDAO' => 'applications/system/storage/PhabricatorSystemDAO.php',
'PhabricatorSystemDestructionGarbageCollector' => 'applications/system/garbagecollector/PhabricatorSystemDestructionGarbageCollector.php',
'PhabricatorSystemDestructionLog' => 'applications/system/storage/PhabricatorSystemDestructionLog.php',
- 'PhabricatorSystemFaviconController' => 'applications/system/controller/PhabricatorSystemFaviconController.php',
'PhabricatorSystemReadOnlyController' => 'applications/system/controller/PhabricatorSystemReadOnlyController.php',
'PhabricatorSystemRemoveDestroyWorkflow' => 'applications/system/management/PhabricatorSystemRemoveDestroyWorkflow.php',
'PhabricatorSystemRemoveLogWorkflow' => 'applications/system/management/PhabricatorSystemRemoveLogWorkflow.php',
@@ -8512,6 +8513,8 @@
'PhabricatorFactObjectDimension' => 'PhabricatorFactDimension',
'PhabricatorFactRaw' => 'PhabricatorFactDAO',
'PhabricatorFactUpdateIterator' => 'PhutilBufferedIterator',
+ 'PhabricatorFaviconRef' => 'Phobject',
+ 'PhabricatorFaviconRefQuery' => 'Phobject',
'PhabricatorFavoritesApplication' => 'PhabricatorApplication',
'PhabricatorFavoritesController' => 'PhabricatorController',
'PhabricatorFavoritesMainMenuBarExtension' => 'PhabricatorMainMenuBarExtension',
@@ -10142,7 +10145,6 @@
'PhabricatorSystemDAO' => 'PhabricatorLiskDAO',
'PhabricatorSystemDestructionGarbageCollector' => 'PhabricatorGarbageCollector',
'PhabricatorSystemDestructionLog' => 'PhabricatorSystemDAO',
- 'PhabricatorSystemFaviconController' => 'PhabricatorController',
'PhabricatorSystemReadOnlyController' => 'PhabricatorController',
'PhabricatorSystemRemoveDestroyWorkflow' => 'PhabricatorSystemRemoveWorkflow',
'PhabricatorSystemRemoveLogWorkflow' => 'PhabricatorSystemRemoveWorkflow',
diff --git a/src/applications/config/option/PhabricatorUIConfigOptions.php b/src/applications/config/option/PhabricatorUIConfigOptions.php
--- a/src/applications/config/option/PhabricatorUIConfigOptions.php
+++ b/src/applications/config/option/PhabricatorUIConfigOptions.php
@@ -64,6 +64,10 @@
"Phabricator logo in the site header.\n\n".
" - **Wordmark**: Choose new text to display next to the logo. ".
"By default, the header displays //Phabricator//.\n\n")),
+ $this->newOption('ui.favicons', 'wild', array())
+ ->setSummary(pht('Customize favicons.'))
+ ->setDescription(pht('Customize favicons.'))
+ ->setLocked(true),
$this->newOption('ui.footer-items', $footer_type, array())
->setSummary(
pht(
diff --git a/src/applications/files/favicon/PhabricatorFaviconRef.php b/src/applications/files/favicon/PhabricatorFaviconRef.php
new file mode 100644
--- /dev/null
+++ b/src/applications/files/favicon/PhabricatorFaviconRef.php
@@ -0,0 +1,447 @@
+<?php
+
+final class PhabricatorFaviconRef extends Phobject {
+
+ private $viewer;
+ private $width;
+ private $height;
+ private $emblems;
+ private $uri;
+ private $cacheKey;
+
+ public function __construct() {
+ $this->emblems = array(null, null, null, null);
+ }
+
+ public function setViewer(PhabricatorUser $viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ public function getViewer() {
+ return $this->viewer;
+ }
+
+ public function setWidth($width) {
+ $this->width = $width;
+ return $this;
+ }
+
+ public function getWidth() {
+ return $this->width;
+ }
+
+ public function setHeight($height) {
+ $this->height = $height;
+ return $this;
+ }
+
+ public function getHeight() {
+ return $this->height;
+ }
+
+ public function setEmblems(array $emblems) {
+ if (count($emblems) !== 4) {
+ throw new Exception(
+ pht(
+ 'Expected four elements in icon emblem list. To omit an emblem, '.
+ 'pass "null".'));
+ }
+
+ $this->emblems = $emblems;
+ return $this;
+ }
+
+ public function getEmblems() {
+ return $this->emblems;
+ }
+
+ public function setURI($uri) {
+ $this->uri = $uri;
+ return $this;
+ }
+
+ public function getURI() {
+ return $this->uri;
+ }
+
+ public function setCacheKey($cache_key) {
+ $this->cacheKey = $cache_key;
+ return $this;
+ }
+
+ public function getCacheKey() {
+ return $this->cacheKey;
+ }
+
+ public function newDigest() {
+ return PhabricatorHash::digestForIndex(serialize($this->toDictionary()));
+ }
+
+ public function toDictionary() {
+ return array(
+ 'width' => $this->width,
+ 'height' => $this->height,
+ 'emblems' => $this->emblems,
+ );
+ }
+
+ public static function newConfigurationDigest() {
+ $all_resources = self::getAllResources();
+
+ // Because we need to access this cache on every page, it's very sticky.
+ // Try to dirty it automatically if any relevant configuration changes.
+ $inputs = array(
+ 'resources' => $all_resources,
+ 'prod' => PhabricatorEnv::getProductionURI('/'),
+ 'cdn' => PhabricatorEnv::getEnvConfig('security.alternate-file-domain'),
+ 'havepng' => function_exists('imagepng'),
+ );
+
+ return PhabricatorHash::digestForIndex(serialize($inputs));
+ }
+
+ private static function getAllResources() {
+ $custom_resources = PhabricatorEnv::getEnvConfig('ui.favicons');
+
+ foreach ($custom_resources as $key => $custom_resource) {
+ $custom_resources[$key] = array(
+ 'source-type' => 'file',
+ 'default' => false,
+ ) + $custom_resource;
+ }
+
+ $builtin_resources = self::getBuiltinResources();
+
+ return array_merge($builtin_resources, $custom_resources);
+ }
+
+ private static function getBuiltinResources() {
+ return array(
+ array(
+ 'source-type' => 'builtin',
+ 'source' => 'favicon/default-76x76.png',
+ 'version' => 1,
+ 'width' => 76,
+ 'height' => 76,
+ 'default' => true,
+ ),
+ array(
+ 'source-type' => 'builtin',
+ 'source' => 'favicon/default-120x120.png',
+ 'version' => 1,
+ 'width' => 120,
+ 'height' => 120,
+ 'default' => true,
+ ),
+ array(
+ 'source-type' => 'builtin',
+ 'source' => 'favicon/default-128x128.png',
+ 'version' => 1,
+ 'width' => 128,
+ 'height' => 128,
+ 'default' => true,
+ ),
+ array(
+ 'source-type' => 'builtin',
+ 'source' => 'favicon/default-152x152.png',
+ 'version' => 1,
+ 'width' => 152,
+ 'height' => 152,
+ 'default' => true,
+ ),
+ array(
+ 'source-type' => 'builtin',
+ 'source' => 'favicon/dot-pink-64x64.png',
+ 'version' => 1,
+ 'width' => 64,
+ 'height' => 64,
+ 'emblem' => 'dot-pink',
+ 'default' => true,
+ ),
+ array(
+ 'source-type' => 'builtin',
+ 'source' => 'favicon/dot-red-64x64.png',
+ 'version' => 1,
+ 'width' => 64,
+ 'height' => 64,
+ 'emblem' => 'dot-red',
+ 'default' => true,
+ ),
+ );
+ }
+
+ public function newURI() {
+ $dst_w = $this->getWidth();
+ $dst_h = $this->getHeight();
+
+ $template = $this->newTemplateFile(null, $dst_w, $dst_h);
+ $template_file = $template['file'];
+
+ $cache = $this->loadCachedFile($template_file);
+ if ($cache) {
+ return $cache->getViewURI();
+ }
+
+ $data = $this->newCompositedFavicon($template);
+
+ $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
+
+ $caught = null;
+ try {
+ $favicon_file = $this->newFaviconFile($data);
+
+ $xform = id(new PhabricatorTransformedFile())
+ ->setOriginalPHID($template_file->getPHID())
+ ->setTransformedPHID($favicon_file->getPHID())
+ ->setTransform($this->getCacheKey());
+
+ try {
+ $xform->save();
+ } catch (AphrontDuplicateKeyQueryException $ex) {
+ unset($unguarded);
+
+ $cache = $this->loadCachedFile($template_file);
+ if (!$cache) {
+ throw $ex;
+ }
+
+ id(new PhabricatorDestructionEngine())
+ ->destroyObject($favicon_file);
+
+ return $cache->getViewURI();
+ }
+ } catch (Exception $ex) {
+ $caught = $ex;
+ }
+
+ unset($unguarded);
+
+ if ($caught) {
+ throw $caught;
+ }
+
+ return $favicon_file->getViewURI();
+ }
+
+ private function loadCachedFile(PhabricatorFile $template_file) {
+ $viewer = $this->getViewer();
+
+ $xform = id(new PhabricatorTransformedFile())->loadOneWhere(
+ 'originalPHID = %s AND transform = %s',
+ $template_file->getPHID(),
+ $this->getCacheKey());
+ if (!$xform) {
+ return null;
+ }
+
+ return id(new PhabricatorFileQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($xform->getTransformedPHID()))
+ ->executeOne();
+ }
+
+ private function newCompositedFavicon($template) {
+ $dst_w = $this->getWidth();
+ $dst_h = $this->getHeight();
+ $src_w = $template['width'];
+ $src_h = $template['height'];
+
+ $template_data = $template['file']->loadFileData();
+
+ if (!function_exists('imagecreatefromstring')) {
+ return $template_data;
+ }
+
+ $src = @imagecreatefromstring($template_data);
+ if (!$src) {
+ return $template_data;
+ }
+
+ $dst = imagecreatetruecolor($dst_w, $dst_h);
+ imagesavealpha($dst, true);
+
+ $transparent = imagecolorallocatealpha($dst, 0, 255, 0, 127);
+ imagefill($dst, 0, 0, $transparent);
+
+ imagecopyresampled(
+ $dst,
+ $src,
+ 0,
+ 0,
+ 0,
+ 0,
+ $dst_w,
+ $dst_h,
+ $src_w,
+ $src_h);
+
+ // Now, copy any icon emblems on top of the image. These are dots or other
+ // marks used to indicate status information.
+ $emblem_w = (int)floor(min($dst_w, $dst_h) / 2);
+ $emblem_h = $emblem_w;
+ foreach ($this->emblems as $key => $emblem) {
+ if ($emblem === null) {
+ continue;
+ }
+
+ $emblem_template = $this->newTemplateFile(
+ $emblem,
+ $emblem_w,
+ $emblem_h);
+
+ switch ($key) {
+ case 0:
+ $emblem_x = $dst_w - $emblem_w;
+ $emblem_y = 0;
+ break;
+ case 1:
+ $emblem_x = $dst_w - $emblem_w;
+ $emblem_y = $dst_h - $emblem_h;
+ break;
+ case 2:
+ $emblem_x = 0;
+ $emblem_y = $dst_h - $emblem_h;
+ break;
+ case 3:
+ $emblem_x = 0;
+ $emblem_y = 0;
+ break;
+ }
+
+ $emblem_data = $emblem_template['file']->loadFileData();
+
+ $src = @imagecreatefromstring($emblem_data);
+ if (!$src) {
+ continue;
+ }
+
+ imagecopyresampled(
+ $dst,
+ $src,
+ $emblem_x,
+ $emblem_y,
+ 0,
+ 0,
+ $emblem_w,
+ $emblem_h,
+ $emblem_template['width'],
+ $emblem_template['height']);
+ }
+
+ return PhabricatorImageTransformer::saveImageDataInAnyFormat(
+ $dst,
+ 'image/png');
+ }
+
+ private function newTemplateFile($emblem, $width, $height) {
+ $all_resources = self::getAllResources();
+
+ $scores = array();
+ $ratio = $width / $height;
+ foreach ($all_resources as $key => $resource) {
+ // We can't use an emblem resource for a different emblem, nor for an
+ // icon base. We also can't use an icon base as an emblem. That is, if
+ // we're looking for a picture of a red dot, we have to actually find
+ // a red dot, not just any image which happens to have a similar size.
+ if (idx($resource, 'emblem') !== $emblem) {
+ continue;
+ }
+
+ $resource_width = $resource['width'];
+ $resource_height = $resource['height'];
+
+ // Never use a resource with a different aspect ratio.
+ if (($resource_width / $resource_height) !== $ratio) {
+ continue;
+ }
+
+ // Try to use custom resources instead of default resources.
+ if ($resource['default']) {
+ $default_score = 1;
+ } else {
+ $default_score = 0;
+ }
+
+ $width_diff = ($resource_width - $width);
+
+ // If we have to resize an image, we'd rather scale a larger image down
+ // than scale a smaller image up.
+ if ($width_diff < 0) {
+ $scale_score = 1;
+ } else {
+ $scale_score = 0;
+ }
+
+ // Otherwise, we'd rather scale an image a little bit (ideally, zero)
+ // than scale an image a lot.
+ $width_score = abs($width_diff);
+
+ $scores[$key] = id(new PhutilSortVector())
+ ->addInt($default_score)
+ ->addInt($scale_score)
+ ->addInt($width_score);
+ }
+
+ if (!$scores) {
+ if ($emblem === null) {
+ throw new Exception(
+ pht(
+ 'Found no background template resource for dimensions %dx%d.',
+ $width,
+ $height));
+ } else {
+ throw new Exception(
+ pht(
+ 'Found no template resource (for emblem "%s") with dimensions '.
+ '%dx%d.',
+ $emblem,
+ $width,
+ $height));
+ }
+ }
+
+ $scores = msortv($scores, 'getSelf');
+ $best_score = head_key($scores);
+
+ $viewer = $this->getViewer();
+
+ $resource = $all_resources[$best_score];
+ if ($resource['source-type'] === 'builtin') {
+ $file = PhabricatorFile::loadBuiltin($viewer, $resource['source']);
+ if (!$file) {
+ throw new Exception(
+ pht(
+ 'Failed to load favicon template builtin "%s".',
+ $resource['source']));
+ }
+ } else {
+ $file = id(new PhabricatorFileQuery())
+ ->setViewer($viewer)
+ ->withPHIDs(array($resource['source']))
+ ->executeOne();
+ if (!$file) {
+ throw new Exception(
+ pht(
+ 'Failed to load favicon template with PHID "%s".',
+ $resource['source']));
+ }
+ }
+
+ return array(
+ 'width' => $resource['width'],
+ 'height' => $resource['height'],
+ 'file' => $file,
+ );
+ }
+
+ private function newFaviconFile($data) {
+ return PhabricatorFile::newFromFileData(
+ $data,
+ array(
+ 'name' => 'favicon',
+ 'canCDN' => true,
+ ));
+ }
+
+}
diff --git a/src/applications/files/favicon/PhabricatorFaviconRefQuery.php b/src/applications/files/favicon/PhabricatorFaviconRefQuery.php
new file mode 100644
--- /dev/null
+++ b/src/applications/files/favicon/PhabricatorFaviconRefQuery.php
@@ -0,0 +1,55 @@
+<?php
+
+final class PhabricatorFaviconRefQuery extends Phobject {
+
+ private $refs;
+
+ public function withRefs(array $refs) {
+ assert_instances_of($refs, 'PhabricatorFaviconRef');
+ $this->refs = $refs;
+ return $this;
+ }
+
+ public function execute() {
+ $viewer = PhabricatorUser::getOmnipotentUser();
+
+ $refs = $this->refs;
+
+ $config_digest = PhabricatorFaviconRef::newConfigurationDigest();
+
+ $ref_map = array();
+ foreach ($refs as $ref) {
+ $ref_digest = $ref->newDigest();
+ $ref_key = "favicon({$config_digest},{$ref_digest},8)";
+
+ $ref
+ ->setViewer($viewer)
+ ->setCacheKey($ref_key);
+
+ $ref_map[$ref_key] = $ref;
+ }
+
+ $cache = PhabricatorCaches::getImmutableCache();
+ $ref_hits = $cache->getKeys(array_keys($ref_map));
+
+ foreach ($ref_hits as $ref_key => $ref_uri) {
+ $ref_map[$ref_key]->setURI($ref_uri);
+ unset($ref_map[$ref_key]);
+ }
+
+ if ($ref_map) {
+ $new_map = array();
+ foreach ($ref_map as $ref_key => $ref) {
+ $ref_uri = $ref->newURI();
+ $ref->setURI($ref_uri);
+ $new_map[$ref_key] = $ref_uri;
+ }
+
+ $cache->setKeys($new_map);
+ }
+
+ return $refs;
+ }
+
+
+}
diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php
--- a/src/applications/files/storage/PhabricatorFile.php
+++ b/src/applications/files/storage/PhabricatorFile.php
@@ -1152,7 +1152,6 @@
$params = array(
'name' => $builtin->getBuiltinDisplayName(),
- 'ttl.relative' => phutil_units('7 days in seconds'),
'canCDN' => true,
'builtin' => $key,
);
@@ -1648,7 +1647,7 @@
public function getFieldValuesForConduit() {
return array(
'name' => $this->getName(),
- 'dataURI' => $this->getCDNURI(),
+ 'dataURI' => $this->getCDNURI('data'),
'size' => (int)$this->getByteSize(),
);
}
diff --git a/src/applications/system/application/PhabricatorSystemApplication.php b/src/applications/system/application/PhabricatorSystemApplication.php
--- a/src/applications/system/application/PhabricatorSystemApplication.php
+++ b/src/applications/system/application/PhabricatorSystemApplication.php
@@ -26,7 +26,6 @@
'/readonly/' => array(
'(?P<reason>[^/]+)/' => 'PhabricatorSystemReadOnlyController',
),
- '/favicon.ico' => 'PhabricatorSystemFaviconController',
);
}
diff --git a/src/applications/system/controller/PhabricatorSystemFaviconController.php b/src/applications/system/controller/PhabricatorSystemFaviconController.php
deleted file mode 100644
--- a/src/applications/system/controller/PhabricatorSystemFaviconController.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<?php
-
-final class PhabricatorSystemFaviconController extends PhabricatorController {
-
- public function shouldRequireLogin() {
- return false;
- }
-
- public function processRequest() {
- $webroot = dirname(phutil_get_library_root('phabricator')).'/webroot/';
- $content = Filesystem::readFile($webroot.'/rsrc/favicons/favicon.ico');
-
- return id(new AphrontFileResponse())
- ->setContent($content)
- ->setMimeType('image/x-icon')
- ->setCacheDurationInSeconds(phutil_units('24 hours in seconds'))
- ->setCanCDN(true);
- }
-}
diff --git a/src/view/page/PhabricatorBarePageView.php b/src/view/page/PhabricatorBarePageView.php
--- a/src/view/page/PhabricatorBarePageView.php
+++ b/src/view/page/PhabricatorBarePageView.php
@@ -71,56 +71,24 @@
));
}
- $mask_icon = phutil_tag(
- 'link',
- array(
- 'rel' => 'mask-icon',
- 'color' => '#3D4B67',
- 'href' => celerity_get_resource_uri(
- '/rsrc/favicons/mask-icon.svg'),
- ));
-
- $icon_tag_76 = phutil_tag(
- 'link',
- array(
- 'rel' => 'apple-touch-icon',
- 'href' => celerity_get_resource_uri(
- '/rsrc/favicons/apple-touch-icon-76x76.png'),
- ));
-
- $icon_tag_120 = phutil_tag(
- 'link',
+ $referrer_tag = phutil_tag(
+ 'meta',
array(
- 'rel' => 'apple-touch-icon',
- 'sizes' => '120x120',
- 'href' => celerity_get_resource_uri(
- '/rsrc/favicons/apple-touch-icon-120x120.png'),
+ 'name' => 'referrer',
+ 'content' => 'no-referrer',
));
- $icon_tag_152 = phutil_tag(
- 'link',
- array(
- 'rel' => 'apple-touch-icon',
- 'sizes' => '152x152',
- 'href' => celerity_get_resource_uri(
- '/rsrc/favicons/apple-touch-icon-152x152.png'),
- ));
- $favicon_tag = phutil_tag(
+ $mask_icon = phutil_tag(
'link',
array(
- 'id' => 'favicon',
- 'rel' => 'shortcut icon',
+ 'rel' => 'mask-icon',
+ 'color' => '#3D4B67',
'href' => celerity_get_resource_uri(
- '/rsrc/favicons/favicon.ico'),
+ '/rsrc/favicons/mask-icon.svg'),
));
- $referrer_tag = phutil_tag(
- 'meta',
- array(
- 'name' => 'referrer',
- 'content' => 'no-referrer',
- ));
+ $favicon_links = $this->newFavicons();
$response = CelerityAPI::getStaticResourceResponse();
@@ -136,13 +104,10 @@
}
return hsprintf(
- '%s%s%s%s%s%s%s%s',
+ '%s%s%s%s%s',
$viewport_tag,
$mask_icon,
- $icon_tag_76,
- $icon_tag_120,
- $icon_tag_152,
- $favicon_tag,
+ $favicon_links,
$referrer_tag,
$response->renderResourcesOfType('css'));
}
@@ -156,4 +121,61 @@
return $response->renderResourcesOfType('js');
}
+ private function newFavicons() {
+ $favicon_refs = array(
+ array(
+ 'rel' => 'apple-touch-icon',
+ 'sizes' => '76x76',
+ 'width' => 76,
+ 'height' => 76,
+ ),
+ array(
+ 'rel' => 'apple-touch-icon',
+ 'sizes' => '120x120',
+ 'width' => 120,
+ 'height' => 120,
+ ),
+ array(
+ 'rel' => 'apple-touch-icon',
+ 'sizes' => '152x152',
+ 'width' => 152,
+ 'height' => 152,
+ ),
+ array(
+ 'rel' => 'icon',
+ 'id' => 'favicon',
+ 'width' => 64,
+ 'height' => 64,
+ ),
+ );
+
+ $fetch_refs = array();
+ foreach ($favicon_refs as $key => $spec) {
+ $ref = id(new PhabricatorFaviconRef())
+ ->setWidth($spec['width'])
+ ->setHeight($spec['height']);
+
+ $favicon_refs[$key]['ref'] = $ref;
+ $fetch_refs[] = $ref;
+ }
+
+ id(new PhabricatorFaviconRefQuery())
+ ->withRefs($fetch_refs)
+ ->execute();
+
+ $favicon_links = array();
+ foreach ($favicon_refs as $spec) {
+ $favicon_links[] = phutil_tag(
+ 'link',
+ array(
+ 'rel' => $spec['rel'],
+ 'sizes' => idx($spec, 'sizes'),
+ 'id' => idx($spec, 'id'),
+ 'href' => $spec['ref']->getURI(),
+ ));
+ }
+
+ return $favicon_links;
+ }
+
}
diff --git a/src/view/page/menu/PhabricatorMainMenuView.php b/src/view/page/menu/PhabricatorMainMenuView.php
--- a/src/view/page/menu/PhabricatorMainMenuView.php
+++ b/src/view/page/menu/PhabricatorMainMenuView.php
@@ -23,15 +23,29 @@
return $this->controller;
}
- private function getFaviconURI($type = null) {
- switch ($type) {
- case 'message':
- return celerity_get_resource_uri('/rsrc/favicons/favicon-message.ico');
- case 'mention':
- return celerity_get_resource_uri('/rsrc/favicons/favicon-mention.ico');
- default:
- return celerity_get_resource_uri('/rsrc/favicons/favicon.ico');
- }
+ private static function getFavicons() {
+ $refs = array();
+
+ $refs['favicon'] = id(new PhabricatorFaviconRef())
+ ->setWidth(64)
+ ->setHeight(64);
+
+ $refs['message_favicon'] = id(new PhabricatorFaviconRef())
+ ->setWidth(64)
+ ->setHeight(64)
+ ->setEmblems(
+ array(
+ 'dot-pink',
+ null,
+ null,
+ null,
+ ));
+
+ id(new PhabricatorFaviconRefQuery())
+ ->withRefs($refs)
+ ->execute();
+
+ return mpull($refs, 'getURI');
}
public function render() {
@@ -428,10 +442,7 @@
'countType' => $conpherence_data['countType'],
'countNumber' => $message_count_number,
'unreadClass' => 'message-unread',
- 'favicon' => $this->getFaviconURI('default'),
- 'message_favicon' => $this->getFaviconURI('message'),
- 'mention_favicon' => $this->getFaviconURI('mention'),
- ));
+ ) + self::getFavicons());
$message_notification_dropdown = javelin_tag(
'div',
@@ -509,10 +520,7 @@
'countType' => $notification_data['countType'],
'countNumber' => $count_number,
'unreadClass' => 'alert-unread',
- 'favicon' => $this->getFaviconURI('default'),
- 'message_favicon' => $this->getFaviconURI('message'),
- 'mention_favicon' => $this->getFaviconURI('mention'),
- ));
+ ) + self::getFavicons());
$notification_dropdown = javelin_tag(
'div',
@@ -594,10 +602,7 @@
'countType' => null,
'countNumber' => null,
'unreadClass' => 'setup-unread',
- 'favicon' => $this->getFaviconURI('default'),
- 'message_favicon' => $this->getFaviconURI('message'),
- 'mention_favicon' => $this->getFaviconURI('mention'),
- ));
+ ) + self::getFavicons());
$setup_notification_dropdown = javelin_tag(
'div',
diff --git a/webroot/favicon.ico b/webroot/favicon.ico
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/apple-touch-icon-114x114.png b/webroot/rsrc/favicons/apple-touch-icon-114x114.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/apple-touch-icon-144x144.png b/webroot/rsrc/favicons/apple-touch-icon-144x144.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/apple-touch-icon-57x57.png b/webroot/rsrc/favicons/apple-touch-icon-57x57.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/apple-touch-icon-60x60.png b/webroot/rsrc/favicons/apple-touch-icon-60x60.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/apple-touch-icon-72x72.png b/webroot/rsrc/favicons/apple-touch-icon-72x72.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/favicon-196x196.png b/webroot/rsrc/favicons/favicon-196x196.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/favicon-32x32.png b/webroot/rsrc/favicons/favicon-32x32.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/favicon-96x96.png b/webroot/rsrc/favicons/favicon-96x96.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/favicon-mention.ico b/webroot/rsrc/favicons/favicon-mention.ico
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/favicon-message.ico b/webroot/rsrc/favicons/favicon-message.ico
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/favicon.ico b/webroot/rsrc/favicons/favicon.ico
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/mstile-144x144.png b/webroot/rsrc/favicons/mstile-144x144.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/mstile-150x150.png b/webroot/rsrc/favicons/mstile-150x150.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/mstile-310x150.png b/webroot/rsrc/favicons/mstile-310x150.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/mstile-310x310.png b/webroot/rsrc/favicons/mstile-310x310.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
diff --git a/webroot/rsrc/favicons/mstile-70x70.png b/webroot/rsrc/favicons/mstile-70x70.png
deleted file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jan 30, 2:15 PM (1 h, 13 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7074801
Default Alt Text
D19209.diff (32 KB)
Attached To
Mode
D19209: Dynamically composite favicons from customizable sources
Attached
Detach File
Event Timeline
Log In to Comment