@@ -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// ----------------------------------------------------------------------
16261680inline void FVTerm::scrollTerminalForward () const
0 commit comments