1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-25 16:22:43 +01:00

Render image diffs as abstract blocks diffs via DocumentEngine

Summary:
Depends on D20830. Ref T13425. Have the image engine elect into block rendering, then emit blocks.

This is rough (the blocks aren't actually diffed yet) but image diffs were already pretty rough so this is approximately a net improvement.

Test Plan: Viewed image diffs, saw nothing worse than before.

Maniphest Tasks: T13425

Differential Revision: https://secure.phabricator.com/D20831
This commit is contained in:
epriestley 2019-09-23 11:09:29 -07:00
parent a73f592d7d
commit bb71ef6ad6
13 changed files with 349 additions and 176 deletions

View file

@ -11,7 +11,7 @@ return array(
'conpherence.pkg.js' => '020aebcf',
'core.pkg.css' => 'c69171e6',
'core.pkg.js' => '6e5c894f',
'differential.pkg.css' => '8d8360fb',
'differential.pkg.css' => 'eef74643',
'differential.pkg.js' => '0b037a4f',
'diffusion.pkg.css' => '42c75c37',
'diffusion.pkg.js' => 'a98c0bf7',
@ -61,7 +61,7 @@ return array(
'rsrc/css/application/dashboard/dashboard.css' => '5a205b9d',
'rsrc/css/application/diff/inline-comment-summary.css' => '81eb368d',
'rsrc/css/application/differential/add-comment.css' => '7e5900d9',
'rsrc/css/application/differential/changeset-view.css' => 'bde53589',
'rsrc/css/application/differential/changeset-view.css' => '215129ef',
'rsrc/css/application/differential/core.css' => '7300a73e',
'rsrc/css/application/differential/phui-inline-comment.css' => '48acce5b',
'rsrc/css/application/differential/revision-comment.css' => '7dbc8d1d',
@ -554,7 +554,7 @@ return array(
'conpherence-thread-manager' => 'aec8e38c',
'conpherence-transaction-css' => '3a3f5e7e',
'd3' => '9d068042',
'differential-changeset-view-css' => 'bde53589',
'differential-changeset-view-css' => '215129ef',
'differential-core-view-css' => '7300a73e',
'differential-revision-add-comment-css' => '7e5900d9',
'differential-revision-comment-css' => '7dbc8d1d',
@ -1069,6 +1069,9 @@ return array(
'javelin-behavior',
'javelin-request',
),
'215129ef' => array(
'phui-inline-comment-view-css',
),
'225bbb98' => array(
'javelin-install',
'javelin-reactor',
@ -1960,9 +1963,6 @@ return array(
'phabricator-drag-and-drop-file-upload',
'javelin-workboard-board',
),
'bde53589' => array(
'phui-inline-comment-view-css',
),
'c03f2fb4' => array(
'javelin-install',
),

View file

@ -3138,6 +3138,8 @@ phutil_register_library_map(array(
'PhabricatorDividerProfileMenuItem' => 'applications/search/menuitem/PhabricatorDividerProfileMenuItem.php',
'PhabricatorDivinerApplication' => 'applications/diviner/application/PhabricatorDivinerApplication.php',
'PhabricatorDocumentEngine' => 'applications/files/document/PhabricatorDocumentEngine.php',
'PhabricatorDocumentEngineBlock' => 'applications/files/diff/PhabricatorDocumentEngineBlock.php',
'PhabricatorDocumentEngineBlocks' => 'applications/files/diff/PhabricatorDocumentEngineBlocks.php',
'PhabricatorDocumentRef' => 'applications/files/document/PhabricatorDocumentRef.php',
'PhabricatorDocumentRenderingEngine' => 'applications/files/document/render/PhabricatorDocumentRenderingEngine.php',
'PhabricatorDoorkeeperApplication' => 'applications/doorkeeper/application/PhabricatorDoorkeeperApplication.php',
@ -9471,6 +9473,8 @@ phutil_register_library_map(array(
'PhabricatorDividerProfileMenuItem' => 'PhabricatorProfileMenuItem',
'PhabricatorDivinerApplication' => 'PhabricatorApplication',
'PhabricatorDocumentEngine' => 'Phobject',
'PhabricatorDocumentEngineBlock' => 'Phobject',
'PhabricatorDocumentEngineBlocks' => 'Phobject',
'PhabricatorDocumentRef' => 'Phobject',
'PhabricatorDocumentRenderingEngine' => 'Phobject',
'PhabricatorDoorkeeperApplication' => 'PhabricatorApplication',

View file

@ -1013,84 +1013,36 @@ final class DifferentialChangesetParser extends Phobject {
->setOldComments($old_comments)
->setNewComments($new_comments);
$engine_view = $this->newDocumentEngineChangesetView();
if ($engine_view !== null) {
return $engine_view;
$engine_blocks = $this->newDocumentEngineChangesetView();
if ($engine_blocks !== null) {
$reference = $this->getRenderingReference();
$parts = explode('/', $reference);
if (count($parts) == 2) {
list($id, $vs) = $parts;
} else {
$id = $parts[0];
$vs = 0;
}
// If we don't have an explicit "vs" changeset, it's the left side of
// the "id" changeset.
if (!$vs) {
$vs = $id;
}
return $renderer->renderDocumentEngineBlocks(
$engine_blocks,
(string)$id,
(string)$vs);
}
// If we've made it here with a type of file we don't know how to render,
// bail out with a default empty rendering. Normally, we'd expect a
// document engine to catch these changes before we make it this far.
switch ($this->changeset->getFileType()) {
case DifferentialChangeType::FILE_IMAGE:
$old = null;
$new = null;
// TODO: Improve the architectural issue as discussed in D955
// https://secure.phabricator.com/D955
$reference = $this->getRenderingReference();
$parts = explode('/', $reference);
if (count($parts) == 2) {
list($id, $vs) = $parts;
} else {
$id = $parts[0];
$vs = 0;
}
$id = (int)$id;
$vs = (int)$vs;
if (!$vs) {
$metadata = $this->changeset->getMetadata();
$data = idx($metadata, 'attachment-data');
$old_phid = idx($metadata, 'old:binary-phid');
$new_phid = idx($metadata, 'new:binary-phid');
} else {
$vs_changeset = id(new DifferentialChangeset())->load($vs);
$old_phid = null;
$new_phid = null;
// TODO: This is spooky, see D6851
if ($vs_changeset) {
$vs_metadata = $vs_changeset->getMetadata();
$old_phid = idx($vs_metadata, 'new:binary-phid');
}
$changeset = id(new DifferentialChangeset())->load($id);
if ($changeset) {
$metadata = $changeset->getMetadata();
$new_phid = idx($metadata, 'new:binary-phid');
}
}
if ($old_phid || $new_phid) {
// grab the files, (micro) optimization for 1 query not 2
$file_phids = array();
if ($old_phid) {
$file_phids[] = $old_phid;
}
if ($new_phid) {
$file_phids[] = $new_phid;
}
$files = id(new PhabricatorFileQuery())
->setViewer($this->getUser())
->withPHIDs($file_phids)
->execute();
foreach ($files as $file) {
if (empty($file)) {
continue;
}
if ($file->getPHID() == $old_phid) {
$old = $file;
} else if ($file->getPHID() == $new_phid) {
$new = $file;
}
}
}
$renderer->attachOldFile($old);
$renderer->attachNewFile($new);
return $renderer->renderFileChange($old, $new, $id, $vs);
case DifferentialChangeType::FILE_DIRECTORY:
case DifferentialChangeType::FILE_BINARY:
case DifferentialChangeType::FILE_IMAGE:
$output = $renderer->renderChangesetTable(null);
return $output;
}
@ -1699,21 +1651,39 @@ final class DifferentialChangesetParser extends Phobject {
return null;
}
$old_data = $this->old;
$old_data = ipull($old_data, 'text');
$old_data = implode('', $old_data);
$old_file = null;
$new_file = null;
$new_data = $this->new;
$new_data = ipull($new_data, 'text');
$new_data = implode('', $new_data);
switch ($changeset->getFileType()) {
case DifferentialChangeType::FILE_IMAGE:
case DifferentialChangeType::FILE_BINARY:
list($old_file, $new_file) = $this->loadFileObjectsForChangeset();
break;
}
$old_ref = id(new PhabricatorDocumentRef())
->setName($changeset->getOldFile())
->setData($old_data);
->setName($changeset->getOldFile());
if ($old_file) {
$old_ref->setFile($old_file);
} else {
$old_data = $this->old;
$old_data = ipull($old_data, 'text');
$old_data = implode('', $old_data);
$old_ref->setData($old_data);
}
$new_ref = id(new PhabricatorDocumentRef())
->setName($changeset->getFilename())
->setData($new_data);
->setName($changeset->getFilename());
if ($new_file) {
$new_ref->setFile($new_file);
} else {
$new_data = $this->new;
$new_data = ipull($new_data, 'text');
$new_data = implode('', $new_data);
$new_ref->setData($old_data);
}
$old_engines = PhabricatorDocumentEngine::getEnginesForRef(
$viewer,
@ -1743,4 +1713,74 @@ final class DifferentialChangesetParser extends Phobject {
return null;
}
private function loadFileObjectsForChangeset() {
$changeset = $this->changeset;
$viewer = $this->getViewer();
$old_file = null;
$new_file = null;
// TODO: Improve the architectural issue as discussed in D955
// https://secure.phabricator.com/D955
$reference = $this->getRenderingReference();
$parts = explode('/', $reference);
if (count($parts) == 2) {
list($id, $vs) = $parts;
} else {
$id = $parts[0];
$vs = 0;
}
$id = (int)$id;
$vs = (int)$vs;
if (!$vs) {
$metadata = $this->changeset->getMetadata();
$data = idx($metadata, 'attachment-data');
$old_phid = idx($metadata, 'old:binary-phid');
$new_phid = idx($metadata, 'new:binary-phid');
} else {
$vs_changeset = id(new DifferentialChangeset())->load($vs);
$old_phid = null;
$new_phid = null;
// TODO: This is spooky, see D6851
if ($vs_changeset) {
$vs_metadata = $vs_changeset->getMetadata();
$old_phid = idx($vs_metadata, 'new:binary-phid');
}
$changeset = id(new DifferentialChangeset())->load($id);
if ($changeset) {
$metadata = $changeset->getMetadata();
$new_phid = idx($metadata, 'new:binary-phid');
}
}
if ($old_phid || $new_phid) {
$file_phids = array();
if ($old_phid) {
$file_phids[] = $old_phid;
}
if ($new_phid) {
$file_phids[] = $new_phid;
}
$files = id(new PhabricatorFileQuery())
->setViewer($viewer)
->withPHIDs($file_phids)
->execute();
foreach ($files as $file) {
if ($file->getPHID() == $old_phid) {
$old_file = $file;
} else if ($file->getPHID() == $new_phid) {
$new_file = $file;
}
}
}
return array($old_file, $new_file);
}
}

View file

@ -608,17 +608,4 @@ abstract class DifferentialChangesetHTMLRenderer
return array($left_prefix, $right_prefix);
}
protected function renderImageStage(PhabricatorFile $file) {
return phutil_tag(
'div',
array(
'class' => 'differential-image-stage',
),
phutil_tag(
'img',
array(
'src' => $file->getBestURI(),
)));
}
}

View file

@ -31,14 +31,6 @@ final class DifferentialChangesetOneUpMailRenderer
return null;
}
public function renderFileChange(
$old_file = null,
$new_file = null,
$id = 0,
$vs = 0) {
return null;
}
public function renderTextChange(
$range_start,
$range_len,

View file

@ -228,34 +228,21 @@ final class DifferentialChangesetOneUpRenderer
return null;
}
public function renderFileChange(
$old_file = null,
$new_file = null,
$id = 0,
$vs = 0) {
public function renderDocumentEngineBlocks(
PhabricatorDocumentEngineBlocks $block_list,
$old_changeset_key,
$new_changeset_key) {
// TODO: This should eventually merge into the normal primitives pathway,
// but fake it for now and just share as much code as possible.
$primitives = array();
if ($old_file) {
foreach ($block_list->newOneUpLayout() as $block) {
$primitives[] = array(
'type' => 'old-file',
'htype' => ($new_file ? 'new-file' : null),
'file' => $old_file,
'htype' => '',
'line' => 1,
'render' => $this->renderImageStage($old_file),
);
}
if ($new_file) {
$primitives[] = array(
'type' => 'new-file',
'htype' => ($old_file ? 'old-file' : null),
'file' => $new_file,
'line' => 1,
'oline' => ($old_file ? 1 : null),
'render' => $this->renderImageStage($new_file),
'render' => $block->newContentView(),
);
}

View file

@ -378,11 +378,13 @@ abstract class DifferentialChangesetRenderer extends Phobject {
$range_start,
$range_len,
$rows);
abstract public function renderFileChange(
$old = null,
$new = null,
$id = 0,
$vs = 0);
public function renderDocumentEngineBlocks(
PhabricatorDocumentEngineBlocks $blocks,
$old_changeset_key,
$new_changeset_key) {
return null;
}
abstract protected function renderChangeTypeHeader($force);
abstract protected function renderUndershieldHeader();

View file

@ -134,14 +134,4 @@ abstract class DifferentialChangesetTestRenderer
return phutil_safe_html($out);
}
public function renderFileChange(
$old_file = null,
$new_file = null,
$id = 0,
$vs = 0) {
throw new PhutilMethodNotImplementedException();
}
}

View file

@ -364,26 +364,28 @@ final class DifferentialChangesetTwoUpRenderer
return $this->wrapChangeInTable(phutil_implode_html('', $html));
}
public function renderFileChange(
$old_file = null,
$new_file = null,
$id = 0,
$vs = 0) {
public function renderDocumentEngineBlocks(
PhabricatorDocumentEngineBlocks $block_list,
$old_changeset_key,
$new_changeset_key) {
$old = null;
if ($old_file) {
$old = $this->renderImageStage($old_file);
}
$old_view = null;
$new_view = null;
$new = null;
if ($new_file) {
$new = $this->renderImageStage($new_file);
}
foreach ($block_list->newTwoUpLayout() as $row) {
list($old, $new) = $row;
// If we don't have an explicit "vs" changeset, it's the left side of the
// "id" changeset.
if (!$vs) {
$vs = $id;
if ($old) {
$old_view = $old->newContentView();
} else {
$old_view = null;
}
if ($new) {
$new_view = $new->newContentView();
} else {
$new_view = null;
}
}
$html_old = array();
@ -405,31 +407,52 @@ final class DifferentialChangesetTwoUpRenderer
}
}
if (!$old) {
$th_old = phutil_tag('th', array());
if ($old_view === null) {
$old_id = null;
$old_label = null;
} else {
$th_old = phutil_tag('th', array('id' => "C{$vs}OL1"), 1);
$old_id = "C{$old_changeset_key}OL1";
$old_label = '1';
}
if (!$new) {
$th_new = phutil_tag('th', array());
$old_cell = phutil_tag(
'td',
array(
'id' => $old_id,
'class' => 'n',
),
$old_label);
if ($new_view === null) {
$new_id = null;
$new_label = null;
} else {
$th_new = phutil_tag('th', array('id' => "C{$id}NL1"), 1);
$new_id = "C{$new_changeset_key}NL1";
$new_label = '1';
}
$new_cell = phutil_tag(
'td',
array(
'id' => $new_id,
'class' => 'n',
),
$new_label);
$output = hsprintf(
'<tr class="differential-image-diff">'.
'%s'.
'<td class="differential-old-image">%s</td>'.
'<td class="differential-old-image diff-image-cell">%s</td>'.
'%s'.
'<td class="differential-new-image" colspan="3">%s</td>'.
'<td class="differential-new-image diff-image-cell" '.
'colspan="3">%s</td>'.
'</tr>'.
'%s'.
'%s',
$th_old,
$old,
$th_new,
$new,
$old_cell,
$old_view,
$new_cell,
$new_view,
phutil_implode_html('', $html_old),
phutil_implode_html('', $html_new));

View file

@ -0,0 +1,21 @@
<?php
final class PhabricatorDocumentEngineBlock
extends Phobject {
private $content;
public function setContent($content) {
$this->content = $content;
return $this;
}
public function getContent() {
return $this->content;
}
public function newContentView() {
return $this->getContent();
}
}

View file

@ -0,0 +1,83 @@
<?php
final class PhabricatorDocumentEngineBlocks
extends Phobject {
private $lists = array();
public function addBlockList(PhabricatorDocumentRef $ref, array $blocks) {
assert_instances_of($blocks, 'PhabricatorDocumentEngineBlock');
$this->lists[] = array(
'ref' => $ref,
'blocks' => array_values($blocks),
);
return $this;
}
public function newTwoUpLayout() {
$rows = array();
$lists = $this->lists;
$idx = 0;
while (true) {
$found_any = false;
$row = array();
foreach ($lists as $list) {
$blocks = $list['blocks'];
$cell = idx($blocks, $idx);
if ($cell !== null) {
$found_any = true;
}
$row[] = $cell;
}
if (!$found_any) {
break;
}
$rows[] = $row;
$idx++;
}
return $rows;
}
public function newOneUpLayout() {
$rows = array();
$lists = $this->lists;
$idx = 0;
while (true) {
$found_any = false;
$row = array();
foreach ($lists as $list) {
$blocks = $list['blocks'];
$cell = idx($blocks, $idx);
if ($cell !== null) {
$found_any = true;
}
if ($cell) {
$rows[] = $cell;
}
}
if (!$found_any) {
break;
}
$idx++;
}
return $rows;
}
}

View file

@ -17,6 +17,50 @@ final class PhabricatorImageDocumentEngine
return (1024 * 1024 * 64);
}
public function canDiffDocuments(
PhabricatorDocumentRef $uref,
PhabricatorDocumentRef $vref) {
// For now, we can only render a rich image diff if both documents have
// their data stored in Files already.
return ($uref->getFile() && $vref->getFile());
}
public function newDiffView(
PhabricatorDocumentRef $uref,
PhabricatorDocumentRef $vref) {
$u_blocks = $this->newDiffBlocks($uref);
$v_blocks = $this->newDiffBlocks($vref);
return id(new PhabricatorDocumentEngineBlocks())
->addBlockList($uref, $u_blocks)
->addBlockList($vref, $v_blocks);
}
private function newDiffBlocks(PhabricatorDocumentRef $ref) {
$blocks = array();
$file = $ref->getFile();
$image_view = phutil_tag(
'div',
array(
'class' => 'differential-image-stage',
),
phutil_tag(
'img',
array(
'src' => $file->getBestURI(),
)));
$blocks[] = id(new PhabricatorDocumentEngineBlock())
->setContent($image_view);
return $blocks;
}
protected function canRenderDocumentType(PhabricatorDocumentRef $ref) {
$file = $ref->getFile();
if ($file) {

View file

@ -282,11 +282,11 @@ td.cov-I {
font-weight: bold;
}
.differential-diff .differential-image-diff {
.differential-diff .diff-image-cell {
background-image: url(/rsrc/image/checker_light.png);
}
.differential-diff .differential-image-diff:hover {
.device-desktop .differential-diff .diff-image-cell:hover {
background-image: url(/rsrc/image/checker_dark.png);
}