Skip to content

Commit 6f21fa6

Browse files
committed
Refactor complex method FVTerm::addLayer()
1 parent f04ab56 commit 6f21fa6

File tree

4 files changed

+190
-116
lines changed

4 files changed

+190
-116
lines changed

final/vterm/fvterm.cpp

Lines changed: 167 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -853,132 +853,28 @@ void FVTerm::addLayer (FTermArea* area) const noexcept
853853
if ( ! area || ! area->visible )
854854
return;
855855

856-
const int area_x = area->position.x;
857-
const int area_y = area->position.y;
858-
const int ol = std::max(0, -area_x); // Outside left
859-
const int vterm_width = vterm->size.width;
860-
const int vterm_height = vterm->size.height;
861-
const int ax = std::max(area_x, 0);
862-
const int width = getFullAreaWidth(area);
863-
const int height = area->minimized ? area->min_size.height : getFullAreaHeight(area);
864-
const int xmax_inside_vterm = vterm_width - area_x - 1;
856+
// Compute geometry and decide early whether to render
857+
LayerGeometry geometry = computeLayerGeometry(area);
865858

866859
// Early exit if area is completely outside vterm
867-
if ( area_y >= vterm_height || ax >= vterm_width || area_y + height <= 0 )
860+
if ( ! isLayerOutsideVTerm(geometry) )
868861
return;
869862

870-
// Calculate actual rendering range (clipped to vterm)
871-
const int y_start = std::max(0, -area_y);
872-
const int y_end = std::min(vterm_height - area_y, height);
873-
874863
// Call the preprocessing handler methods (child area change handling)
875864
callPreprocessingHandler(area);
876865

866+
// Create a stack by combining identical rows in sequence
877867
line_changes_batch.clear(); // Clear buffer
878-
int prev_xmin{-1};
879-
int prev_xmax{-1};
880-
NoTrans prev_has_no_trans{NoTrans::Undefined};
881-
882-
auto line_changes = &area->changes_in_line[unsigned(y_start)];
883-
884-
for (auto y{y_start}; y < y_end; y++) // Line loop
885-
{
886-
const auto line_xmin_raw = int(line_changes->xmin);
887-
const auto line_xmax_raw = int(line_changes->xmax);
888-
889-
if ( line_xmin_raw > line_xmax_raw )
890-
{
891-
++line_changes;
892-
prev_xmin = -1;
893-
prev_xmax = -1;
894-
prev_has_no_trans = NoTrans::Undefined;
895-
continue;
896-
}
897-
898-
const auto line_xmin = std::max(line_xmin_raw, ol);
899-
const auto line_xmax = std::min(line_xmax_raw, xmax_inside_vterm);
900-
901-
if ( line_xmin > line_xmax )
902-
{
903-
++line_changes;
904-
prev_xmin = -1;
905-
prev_xmax = -1;
906-
prev_has_no_trans = NoTrans::Undefined;
907-
continue;
908-
}
909-
910-
const NoTrans has_no_trans = line_changes->trans_count == 0 ? NoTrans::Set : NoTrans::Unset;
911-
++line_changes;
912-
913-
if ( prev_xmin == line_xmin
914-
&& prev_xmax == line_xmax
915-
&& prev_has_no_trans == has_no_trans )
916-
{
917-
line_changes_batch.back().count++;
918-
continue;
919-
}
920-
921-
line_changes_batch.push_back({1, y, line_xmin, line_xmax, has_no_trans});
922-
prev_xmin = line_xmin;
923-
prev_xmax = line_xmax;
924-
prev_has_no_trans = has_no_trans;
925-
}
868+
buildLineChangeBatch(area, geometry);
926869

927870
if ( line_changes_batch.empty() )
928871
return;
929872

930-
for (const auto& line : line_changes_batch)
931-
{
932-
const auto line_xmin = static_cast<unsigned>(line.xmin);
933-
const auto line_xmax = static_cast<unsigned>(line.xmax);
934-
const auto has_no_trans = line.has_no_transparency == NoTrans::Set;
935-
const auto tx = unsigned(area_x) + line_xmin; // Global terminal x-position
936-
const std::size_t length = line_xmax - line_xmin + 1;
873+
// Apply the batches to vterm data
874+
applyLineBatch(area, geometry);
937875

938-
// Process all lines in batch with same operation
939-
for (int i = 0; i < line.count; ++i)
940-
{
941-
const auto y = static_cast<unsigned>(line.ypos + i);
942-
line_changes = &area->changes_in_line[y];
943-
const auto ty = unsigned(area_y) + y; // Global terminal y-position
944-
const auto area_line_offset = y * unsigned(width) + line_xmin;
945-
const auto vterm_line_offset = ty * unsigned(vterm_width) + tx;
946-
const auto* ac = &area->data[area_line_offset]; // Area character
947-
auto* tc = &vterm->data[vterm_line_offset]; // Terminal character
948-
949-
if ( has_no_trans )
950-
{
951-
// Line has only covered characters
952-
putAreaLine (*ac, *tc, length);
953-
}
954-
else
955-
{
956-
// Line with hidden and transparent characters
957-
addAreaLineWithTransparency (ac, tc, length);
958-
}
959-
960-
auto& vterm_changes = vterm->changes_in_line[ty];
961-
const auto tx_start = uInt(tx);
962-
const auto tx_end = uInt(std::min( unsigned(ax) + line_xmax
963-
, unsigned(vterm_width - 1) ));
964-
vterm_changes.xmin = std::min(vterm_changes.xmin, tx_start);
965-
vterm_changes.xmax = std::max(vterm_changes.xmax, tx_end);
966-
967-
line_changes->xmin = uInt(width);
968-
line_changes->xmax = 0;
969-
++line_changes;
970-
}
971-
}
972-
973-
const auto& first = line_changes_batch.front();
974-
const auto& last = line_changes_batch.back();
975-
const auto begin = uInt(area_y + first.ypos - y_start);
976-
const auto end = uInt(area_y + last.ypos + last.count - 1 - y_start);
977-
978-
auto& changes_in_row = vterm->changes_in_row;
979-
changes_in_row.ymin = std::min(changes_in_row.ymin, begin);
980-
changes_in_row.ymax = std::max(changes_in_row.ymax, end);
981-
vterm->has_changes = true;
876+
// Update the range of changed rows and the cursor on vterm
877+
updateVTermChangesFromBatch(geometry);
982878
updateVTermCursor(area);
983879
}
984880

@@ -1621,6 +1517,164 @@ inline void FVTerm::updateVTermWindow (FTermArea* v_win) const
16211517
clearChildAreaChanges(v_win);
16221518
}
16231519
}
1520+
//----------------------------------------------------------------------
1521+
inline auto FVTerm::computeLayerGeometry (const FTermArea* area) const noexcept -> LayerGeometry
1522+
{
1523+
// Compute the geometry values used throughout the rendering process
1524+
1525+
const auto area_x = area->position.x;
1526+
const auto area_y = area->position.y;
1527+
const auto vterm_width = unsigned(vterm->size.width);
1528+
const auto vterm_height = unsigned(vterm->size.height);
1529+
const auto height = area->minimized ? area->min_size.height : getFullAreaHeight(area);
1530+
1531+
return LayerGeometry
1532+
{
1533+
area_x,
1534+
area_y,
1535+
std::max(0, -area_x),
1536+
vterm_width,
1537+
vterm_height,
1538+
static_cast<unsigned>(std::max(area_x, 0)),
1539+
getFullAreaWidth(area),
1540+
height,
1541+
static_cast<int>(vterm_width) - area_x - 1,
1542+
// Calculate actual rendering range (clipped to vterm)
1543+
std::max(0, -area_y),
1544+
std::min(static_cast<int>(vterm_height) - area_y, height)
1545+
};
1546+
}
1547+
1548+
//----------------------------------------------------------------------
1549+
inline auto FVTerm::isLayerOutsideVTerm (const LayerGeometry& geo) const noexcept -> bool
1550+
{
1551+
if ( geo.area_y >= static_cast<int>(geo.vterm_height) )
1552+
return false;
1553+
1554+
if ( geo.ax >= geo.vterm_width )
1555+
return false;
1556+
1557+
if ( geo.area_y + geo.height <= 0 )
1558+
return false;
1559+
1560+
return true;
1561+
}
1562+
1563+
//----------------------------------------------------------------------
1564+
inline void FVTerm::buildLineChangeBatch ( const FTermArea* area
1565+
, const LayerGeometry& geo ) const noexcept
1566+
{
1567+
int prev_xmin{-1};
1568+
int prev_xmax{-1};
1569+
NoTrans prev_has_no_trans{NoTrans::Undefined};
1570+
1571+
auto line_changes = &area->changes_in_line[unsigned(geo.y_start)];
1572+
1573+
for (auto y{geo.y_start}; y < geo.y_end; y++) // Line loop
1574+
{
1575+
const auto line_xmin_raw = int(line_changes->xmin);
1576+
const auto line_xmax_raw = int(line_changes->xmax);
1577+
1578+
if ( line_xmin_raw > line_xmax_raw )
1579+
{
1580+
++line_changes;
1581+
prev_xmin = -1;
1582+
prev_xmax = -1;
1583+
prev_has_no_trans = NoTrans::Undefined;
1584+
continue;
1585+
}
1586+
1587+
const auto line_xmin = std::max(line_xmin_raw, geo.ol);
1588+
const auto line_xmax = std::min(line_xmax_raw, geo.xmax_inside_vterm);
1589+
1590+
if ( line_xmin > line_xmax )
1591+
{
1592+
++line_changes;
1593+
prev_xmin = -1;
1594+
prev_xmax = -1;
1595+
prev_has_no_trans = NoTrans::Undefined;
1596+
continue;
1597+
}
1598+
1599+
const NoTrans has_no_trans = line_changes->trans_count == 0 ? NoTrans::Set : NoTrans::Unset;
1600+
++line_changes;
1601+
1602+
if ( prev_xmin == line_xmin
1603+
&& prev_xmax == line_xmax
1604+
&& prev_has_no_trans == has_no_trans )
1605+
{
1606+
line_changes_batch.back().count++;
1607+
continue;
1608+
}
1609+
1610+
line_changes_batch.push_back({1, y, line_xmin, line_xmax, has_no_trans});
1611+
prev_xmin = line_xmin;
1612+
prev_xmax = line_xmax;
1613+
prev_has_no_trans = has_no_trans;
1614+
}
1615+
}
1616+
1617+
//----------------------------------------------------------------------
1618+
inline void FVTerm::applyLineBatch ( FTermArea* area
1619+
, const LayerGeometry& geo ) const noexcept
1620+
{
1621+
for (const auto& line : line_changes_batch)
1622+
{
1623+
const auto line_xmin = static_cast<unsigned>(line.xmin);
1624+
const auto line_xmax = static_cast<unsigned>(line.xmax);
1625+
const auto has_no_trans = line.has_no_transparency == NoTrans::Set;
1626+
const auto tx = unsigned(geo.area_x) + line_xmin; // Global terminal x-position
1627+
const std::size_t length = line_xmax - line_xmin + 1;
1628+
1629+
// Process all lines in batch with same operation
1630+
for (int i = 0; i < line.count; ++i)
1631+
{
1632+
const auto y = static_cast<unsigned>(line.ypos + i);
1633+
auto line_changes = &area->changes_in_line[y];
1634+
const auto ty = unsigned(geo.area_y) + y; // Global terminal y-position
1635+
const auto area_line_offset = y * unsigned(geo.width) + line_xmin;
1636+
const auto vterm_line_offset = ty * geo.vterm_width + tx;
1637+
const auto* ac = &area->data[area_line_offset]; // Area character
1638+
auto* tc = &vterm->data[vterm_line_offset]; // Terminal character
1639+
1640+
if ( has_no_trans )
1641+
{
1642+
// Line has only covered characters
1643+
putAreaLine (*ac, *tc, length);
1644+
}
1645+
else
1646+
{
1647+
// Line with hidden and transparent characters
1648+
addAreaLineWithTransparency (ac, tc, length);
1649+
}
1650+
1651+
auto& vterm_changes = vterm->changes_in_line[ty];
1652+
const auto tx_start = uInt(tx);
1653+
const auto tx_end = uInt(std::min( geo.ax + line_xmax
1654+
, geo.vterm_width - 1 ));
1655+
vterm_changes.xmin = std::min(vterm_changes.xmin, tx_start);
1656+
vterm_changes.xmax = std::max(vterm_changes.xmax, tx_end);
1657+
1658+
line_changes->xmin = uInt(geo.width);
1659+
line_changes->xmax = 0;
1660+
++line_changes;
1661+
}
1662+
}
1663+
}
1664+
1665+
//----------------------------------------------------------------------
1666+
inline void FVTerm::updateVTermChangesFromBatch (const LayerGeometry& geo) const noexcept
1667+
{
1668+
const auto& first = line_changes_batch.front();
1669+
const auto& last = line_changes_batch.back();
1670+
const auto begin = uInt(geo.area_y + first.ypos - geo.y_start);
1671+
const auto end = uInt(geo.area_y + last.ypos + last.count - 1 - geo.y_start);
1672+
1673+
auto& changes_in_row = vterm->changes_in_row;
1674+
changes_in_row.ymin = std::min(changes_in_row.ymin, begin);
1675+
changes_in_row.ymax = std::max(changes_in_row.ymax, end);
1676+
vterm->has_changes = true;
1677+
}
16241678

16251679
//----------------------------------------------------------------------
16261680
inline void FVTerm::scrollTerminalForward() const

final/vterm/fvterm.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,21 @@ class FVTerm : public FVTermAttribute
264264
virtual void initTerminal();
265265

266266
private:
267+
struct LayerGeometry
268+
{
269+
int area_x;
270+
int area_y;
271+
int ol; // Outside-left
272+
unsigned vterm_width;
273+
unsigned vterm_height;
274+
unsigned ax; // Clipped area x (>=0)
275+
int width; // Full area width
276+
int height; // Effective area height (minimized or full)
277+
int xmax_inside_vterm;
278+
int y_start;
279+
int y_end;
280+
};
281+
267282
struct AreaLine
268283
{
269284
const FChar* data; // Source drawing area line
@@ -339,6 +354,11 @@ class FVTerm : public FVTermAttribute
339354
void updateVTerm() const;
340355
void updateVTermDesktop() const;
341356
void updateVTermWindow (FTermArea*) const;
357+
auto computeLayerGeometry (const FTermArea*) const noexcept -> LayerGeometry;
358+
auto isLayerOutsideVTerm (const LayerGeometry&) const noexcept -> bool;
359+
void buildLineChangeBatch (const FTermArea*, const LayerGeometry&) const noexcept;
360+
void applyLineBatch (FTermArea*, const LayerGeometry&) const noexcept;
361+
void updateVTermChangesFromBatch (const LayerGeometry&) const noexcept;
342362
void scrollTerminalForward() const;
343363
void scrollTerminalReverse() const;
344364
void callPreprocessingHandler (const FTermArea*) const;

scripts/cppcheck.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
if [ $# -gt 0 ]
44
then
5-
eval cppcheck --force --language=c++ --std=c++14 --enable=all -I../ "$@"
5+
cppcheck --force --language=c++ --std=c++14 --enable=all -I../ "$@"
66
else
7-
eval cppcheck --force --language=c++ --std=c++14 --enable=all -I../ ../final/ ../examples/
7+
cppcheck --force --language=c++ --std=c++14 --enable=all -I../ ../final/ ../examples/
88
fi
99

test/fvterm-test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2073,7 +2073,7 @@ void FVTermTest::FVTermChildAreaPrintTest()
20732073
<< finalcut::FPoint(36, 9) << L"= ="
20742074
<< finalcut::FPoint(36, 10) << L"= ="
20752075
<< finalcut::FPoint(36, 11) << L"==========";
2076-
2076+
20772077
CPPUNIT_ASSERT ( vwin->has_changes );
20782078
test::printArea (vwin);
20792079

0 commit comments

Comments
 (0)