diff --git a/resources/sql/autopatches/20150819.macrooriginalsize.1.sql b/resources/sql/autopatches/20150819.macrooriginalsize.1.sql new file mode 100644 --- /dev/null +++ b/resources/sql/autopatches/20150819.macrooriginalsize.1.sql @@ -0,0 +1,2 @@ +ALTER TABLE {$NAMESPACE}_file.file_imagemacro + ADD useOriginalSize TINYINT(1) DEFAULT 0 NOT NULL; 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 @@ -2240,6 +2240,7 @@ 'PhabricatorMacroManageCapability' => 'applications/macro/capability/PhabricatorMacroManageCapability.php', 'PhabricatorMacroMemeController' => 'applications/macro/controller/PhabricatorMacroMemeController.php', 'PhabricatorMacroMemeDialogController' => 'applications/macro/controller/PhabricatorMacroMemeDialogController.php', + 'PhabricatorMacroOriginalSizeController' => 'applications/macro/controller/PhabricatorMacroOriginalSizeController.php', 'PhabricatorMacroQuery' => 'applications/macro/query/PhabricatorMacroQuery.php', 'PhabricatorMacroReplyHandler' => 'applications/macro/mail/PhabricatorMacroReplyHandler.php', 'PhabricatorMacroSearchEngine' => 'applications/macro/query/PhabricatorMacroSearchEngine.php', @@ -6180,6 +6181,7 @@ 'PhabricatorMacroManageCapability' => 'PhabricatorPolicyCapability', 'PhabricatorMacroMemeController' => 'PhabricatorMacroController', 'PhabricatorMacroMemeDialogController' => 'PhabricatorMacroController', + 'PhabricatorMacroOriginalSizeController' => 'PhabricatorMacroController', 'PhabricatorMacroQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorMacroReplyHandler' => 'PhabricatorApplicationTransactionReplyHandler', 'PhabricatorMacroSearchEngine' => 'PhabricatorApplicationSearchEngine', diff --git a/src/applications/files/transform/PhabricatorFileThumbnailTransform.php b/src/applications/files/transform/PhabricatorFileThumbnailTransform.php --- a/src/applications/files/transform/PhabricatorFileThumbnailTransform.php +++ b/src/applications/files/transform/PhabricatorFileThumbnailTransform.php @@ -7,12 +7,14 @@ const TRANSFORM_PINBOARD = 'pinboard'; const TRANSFORM_THUMBGRID = 'thumbgrid'; const TRANSFORM_PREVIEW = 'preview'; + const TRANSFORM_MACRO = 'macro'; private $name; private $key; private $dstX; private $dstY; private $scaleUp; + private $preserveAspectRatio; public function setName($name) { $this->name = $name; @@ -35,6 +37,11 @@ return $this; } + public function setPreserveAspectRatio($preserve_aspect_ratio) { + $this->preserveAspectRatio = $preserve_aspect_ratio; + return $this; + } + public function getTransformName() { return $this->name; } @@ -73,6 +80,11 @@ ->setName(pht('Preview (220px)')) ->setKey(self::TRANSFORM_PREVIEW) ->setDimensions(220, null), + id(new PhabricatorFileThumbnailTransform()) + ->setName(pht('Macro (400px)')) + ->setKey(self::TRANSFORM_MACRO) + ->setDimensions(400, 400) + ->setPreserveAspectRatio(true), ); } @@ -83,6 +95,15 @@ $dst_x = $this->dstX; $dst_y = $this->dstY; + if ($this->preserveAspectRatio) { + if ($src_x < $src_y && $src_y > $dst_y) { + $ratio = $dst_y / $src_y; + $dst_x = $src_x * $ratio; + } else { + $dst_y = null; + } + } + $dimensions = $this->computeDimensions( $src_x, $src_y, diff --git a/src/applications/macro/application/PhabricatorMacroApplication.php b/src/applications/macro/application/PhabricatorMacroApplication.php --- a/src/applications/macro/application/PhabricatorMacroApplication.php +++ b/src/applications/macro/application/PhabricatorMacroApplication.php @@ -36,6 +36,8 @@ 'edit/(?P[1-9]\d*)/' => 'PhabricatorMacroEditController', 'audio/(?P[1-9]\d*)/' => 'PhabricatorMacroAudioController', 'disable/(?P[1-9]\d*)/' => 'PhabricatorMacroDisableController', + 'originalsize/(?P[1-9]\d*)/' => + 'PhabricatorMacroOriginalSizeController', 'meme/' => 'PhabricatorMacroMemeController', 'meme/create/' => 'PhabricatorMacroMemeDialogController', ), diff --git a/src/applications/macro/controller/PhabricatorMacroMemeController.php b/src/applications/macro/controller/PhabricatorMacroMemeController.php --- a/src/applications/macro/controller/PhabricatorMacroMemeController.php +++ b/src/applications/macro/controller/PhabricatorMacroMemeController.php @@ -43,13 +43,20 @@ ->loadOneWhere('originalphid=%s and transform=%s', $file->getPHID(), $hash); + $preview_key = PhabricatorFileThumbnailTransform::TRANSFORM_MACRO; + $xform_preview = PhabricatorFileTransform::getTransformByKey($preview_key); + if ($xform) { $memefile = id(new PhabricatorFileQuery()) ->setViewer($viewer) ->withPHIDs(array($xform->getTransformedPHID())) ->executeOne(); if ($memefile) { - return $memefile->getBestURI(); + if ($macro->getUseOriginalSize()) { + return $memefile->getBestURI(); + } else { + return $memefile->getURIForTransform($xform_preview); + } } } @@ -63,6 +70,10 @@ $xfile->setTransform($hash); $xfile->save(); - return $newfile->getBestURI(); + if ($macro->getUseOriginalSize()) { + return $newfile->getBestURI(); + } else { + return $newfile->getURIForTransform($xform_preview); + } } } diff --git a/src/applications/macro/controller/PhabricatorMacroOriginalSizeController.php b/src/applications/macro/controller/PhabricatorMacroOriginalSizeController.php new file mode 100644 --- /dev/null +++ b/src/applications/macro/controller/PhabricatorMacroOriginalSizeController.php @@ -0,0 +1,54 @@ +getViewer(); + $id = $request->getURIData('id'); + + $this->requireApplicationCapability( + PhabricatorMacroManageCapability::CAPABILITY); + + $macro = id(new PhabricatorMacroQuery()) + ->setViewer($viewer) + ->withIDs(array($id)) + ->needFiles(true) + ->executeOne(); + if (!$macro) { + return new Aphront404Response(); + } + + $view_uri = $this->getApplicationURI('/view/'.$id.'/'); + + if ($macro->getFile()->getMimeType() === 'image/gif') { + $dialog = new AphrontDialogView(); + $dialog + ->setUser($request->getUser()) + ->setTitle(pht('Animated macros can not be resized')) + ->appendChild( + phutil_tag( + 'p', + array(), + pht( + 'Sorry, but animated macros can not be '. + 'automatically resized by Phabricator.'))) + ->addCancelButton($view_uri); + + return id(new AphrontDialogResponse())->setDialog($dialog); + } + + $xaction = id(new PhabricatorMacroTransaction()) + ->setTransactionType(PhabricatorMacroTransaction::TYPE_ORIGINAL_SIZE) + ->setNewValue($macro->getUseOriginalSize() ? 0 : 1); + + $editor = id(new PhabricatorMacroEditor()) + ->setActor($viewer) + ->setContentSourceFromRequest($request); + + $xactions = $editor->applyTransactions($macro, array($xaction)); + + return id(new AphrontRedirectResponse())->setURI($view_uri); + } + +} diff --git a/src/applications/macro/controller/PhabricatorMacroViewController.php b/src/applications/macro/controller/PhabricatorMacroViewController.php --- a/src/applications/macro/controller/PhabricatorMacroViewController.php +++ b/src/applications/macro/controller/PhabricatorMacroViewController.php @@ -138,6 +138,35 @@ ->setIcon('fa-ban')); } + if ($macro->getFile()->getMimeType() === 'image/gif') { + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Automatically Resize')) + ->setHref( + $this->getApplicationURI('/originalsize/'.$macro->getID().'/')) + ->setWorkflow(true) + ->setDisabled(true) + ->setIcon('fa-compress')); + } else if ($macro->getUseOriginalSize()) { + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Automatically Resize')) + ->setHref( + $this->getApplicationURI('/originalsize/'.$macro->getID().'/')) + ->setWorkflow(true) + ->setDisabled(!$can_manage) + ->setIcon('fa-compress')); + } else { + $view->addAction( + id(new PhabricatorActionView()) + ->setName(pht('Use Original Size')) + ->setHref( + $this->getApplicationURI('/originalsize/'.$macro->getID().'/')) + ->setWorkflow(true) + ->setDisabled(!$can_manage) + ->setIcon('fa-expand')); + } + return $view; } diff --git a/src/applications/macro/editor/PhabricatorMacroEditor.php b/src/applications/macro/editor/PhabricatorMacroEditor.php --- a/src/applications/macro/editor/PhabricatorMacroEditor.php +++ b/src/applications/macro/editor/PhabricatorMacroEditor.php @@ -17,6 +17,7 @@ $types[] = PhabricatorTransactions::TYPE_COMMENT; $types[] = PhabricatorMacroTransaction::TYPE_NAME; $types[] = PhabricatorMacroTransaction::TYPE_DISABLED; + $types[] = PhabricatorMacroTransaction::TYPE_ORIGINAL_SIZE; $types[] = PhabricatorMacroTransaction::TYPE_FILE; $types[] = PhabricatorMacroTransaction::TYPE_AUDIO; $types[] = PhabricatorMacroTransaction::TYPE_AUDIO_BEHAVIOR; @@ -33,6 +34,8 @@ return $object->getName(); case PhabricatorMacroTransaction::TYPE_DISABLED: return $object->getIsDisabled(); + case PhabricatorMacroTransaction::TYPE_ORIGINAL_SIZE: + return $object->getUseOriginalSize(); case PhabricatorMacroTransaction::TYPE_FILE: return $object->getFilePHID(); case PhabricatorMacroTransaction::TYPE_AUDIO: @@ -49,6 +52,7 @@ switch ($xaction->getTransactionType()) { case PhabricatorMacroTransaction::TYPE_NAME: case PhabricatorMacroTransaction::TYPE_DISABLED: + case PhabricatorMacroTransaction::TYPE_ORIGINAL_SIZE: case PhabricatorMacroTransaction::TYPE_FILE: case PhabricatorMacroTransaction::TYPE_AUDIO: case PhabricatorMacroTransaction::TYPE_AUDIO_BEHAVIOR: @@ -67,6 +71,9 @@ case PhabricatorMacroTransaction::TYPE_DISABLED: $object->setIsDisabled($xaction->getNewValue()); break; + case PhabricatorMacroTransaction::TYPE_ORIGINAL_SIZE: + $object->setUseOriginalSize($xaction->getNewValue()); + break; case PhabricatorMacroTransaction::TYPE_FILE: $object->setFilePHID($xaction->getNewValue()); break; @@ -125,6 +132,7 @@ switch ($type) { case PhabricatorMacroTransaction::TYPE_NAME: case PhabricatorMacroTransaction::TYPE_DISABLED: + case PhabricatorMacroTransaction::TYPE_ORIGINAL_SIZE: case PhabricatorMacroTransaction::TYPE_FILE: case PhabricatorMacroTransaction::TYPE_AUDIO: case PhabricatorMacroTransaction::TYPE_AUDIO_BEHAVIOR: diff --git a/src/applications/macro/markup/PhabricatorImageMacroRemarkupRule.php b/src/applications/macro/markup/PhabricatorImageMacroRemarkupRule.php --- a/src/applications/macro/markup/PhabricatorImageMacroRemarkupRule.php +++ b/src/applications/macro/markup/PhabricatorImageMacroRemarkupRule.php @@ -136,15 +136,36 @@ )); } + $dimensions_width = $file->getImageWidth(); + $dimensions_height = $file->getImageHeight(); + if ($file->getMimeType() !== 'image/gif' && + !$macro->getUseOriginalSize()) { + $preview_key = PhabricatorFileThumbnailTransform::TRANSFORM_MACRO; + $xform = PhabricatorFileTransform::getTransformByKey($preview_key); + + $dimensions = $xform->getTransformedDimensions($file); + if ($dimensions) { + list($x, $y) = $dimensions; + $dimensions_width = $x; + $dimensions_height = $y; + } + + $uri = $file->getURIForTransform($xform); + } else { + $uri = $file->getBestURI(); + } + + $image_class = 'phabricator-remarkup-embed-image'; + $result = $this->newTag( 'img', array( 'id' => $id, - 'src' => $src_uri, + 'src' => $uri, 'alt' => $spec['original'], 'title' => $spec['original'], - 'height' => $file->getImageHeight(), - 'width' => $file->getImageWidth(), + 'height' => $dimensions_height, + 'width' => $dimensions_width, 'class' => 'phabricator-remarkup-macro', )); diff --git a/src/applications/macro/storage/PhabricatorFileImageMacro.php b/src/applications/macro/storage/PhabricatorFileImageMacro.php --- a/src/applications/macro/storage/PhabricatorFileImageMacro.php +++ b/src/applications/macro/storage/PhabricatorFileImageMacro.php @@ -15,6 +15,7 @@ protected $audioPHID; protected $audioBehavior = self::AUDIO_BEHAVIOR_NONE; protected $mailKey; + protected $useOriginalSize; private $file = self::ATTACHABLE; private $audio = self::ATTACHABLE; @@ -51,6 +52,7 @@ 'audioPHID' => 'phid?', 'audioBehavior' => 'text64', 'mailKey' => 'bytes20', + 'useOriginalSize' => 'bool', ), self::CONFIG_KEY_SCHEMA => array( 'name' => array( diff --git a/src/applications/macro/storage/PhabricatorMacroTransaction.php b/src/applications/macro/storage/PhabricatorMacroTransaction.php --- a/src/applications/macro/storage/PhabricatorMacroTransaction.php +++ b/src/applications/macro/storage/PhabricatorMacroTransaction.php @@ -3,9 +3,10 @@ final class PhabricatorMacroTransaction extends PhabricatorApplicationTransaction { - const TYPE_NAME = 'macro:name'; - const TYPE_DISABLED = 'macro:disabled'; - const TYPE_FILE = 'macro:file'; + const TYPE_NAME = 'macro:name'; + const TYPE_DISABLED = 'macro:disabled'; + const TYPE_FILE = 'macro:file'; + const TYPE_ORIGINAL_SIZE = 'macro:originalsize'; const TYPE_AUDIO = 'macro:audio'; const TYPE_AUDIO_BEHAVIOR = 'macro:audiobehavior'; @@ -83,6 +84,18 @@ } break; + case self::TYPE_ORIGINAL_SIZE: + if ($new) { + return pht( + '%s configured this macro to render as it\'s original size.', + $this->renderHandleLink($author_phid)); + } else { + return pht( + '%s configured this macro to automatically resize.', + $this->renderHandleLink($author_phid)); + } + break; + case self::TYPE_AUDIO: if (!$old) { return pht( @@ -158,6 +171,18 @@ $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } + case self::TYPE_ORIGINAL_SIZE: + if ($new) { + return pht( + '%s configured %s to render as it\'s original size.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + } else { + return pht( + '%s configured %s to automatically resize.', + $this->renderHandleLink($author_phid), + $this->renderHandleLink($object_phid)); + } case self::TYPE_FILE: if ($old === null) { return pht( @@ -228,6 +253,8 @@ } else { return pht('Restored'); } + case self::TYPE_ORIGINAL_SIZE: + return pht('Configured Original Size'); case self::TYPE_FILE: if ($old === null) { return pht('Created'); @@ -275,6 +302,12 @@ } else { return 'fa-undo'; } + case self::TYPE_ORIGINAL_SIZE: + if ($new) { + return 'fa-expand'; + } else { + return 'fa-compress'; + } case self::TYPE_AUDIO: return 'fa-headphones'; }