Line data Source code
1 : /*
2 : Mosh: the mobile shell
3 : Copyright 2012 Keith Winstein
4 :
5 : This program is free software: you can redistribute it and/or modify
6 : it under the terms of the GNU General Public License as published by
7 : the Free Software Foundation, either version 3 of the License, or
8 : (at your option) any later version.
9 :
10 : This program is distributed in the hope that it will be useful,
11 : but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public License
16 : along with this program. If not, see <http://www.gnu.org/licenses/>.
17 :
18 : In addition, as a special exception, the copyright holders give
19 : permission to link the code of portions of this program with the
20 : OpenSSL library under certain conditions as described in each
21 : individual source file, and distribute linked combinations including
22 : the two.
23 :
24 : You must obey the GNU General Public License in all respects for all
25 : of the code used other than OpenSSL. If you modify file(s) with this
26 : exception, you may extend this exception to your version of the
27 : file(s), but you are not obligated to do so. If you do not wish to do
28 : so, delete this exception statement from your version. If you delete
29 : this exception statement from all source files in the program, then
30 : also delete it here.
31 : */
32 :
33 : #include <assert.h>
34 : #include <stdio.h>
35 : #include <stdlib.h>
36 :
37 : #include "terminalframebuffer.h"
38 :
39 : using namespace Terminal;
40 :
41 23883993 : Cell::Cell( color_type background_color )
42 23881689 : : contents(),
43 23883993 : renditions( background_color ),
44 23883993 : wide( false ),
45 23883993 : fallback( false ),
46 23883993 : wrap( false )
47 2304 : {}
48 :
49 24451736 : void Cell::reset( color_type background_color )
50 : {
51 24451736 : contents.clear();
52 24451736 : renditions = Renditions( background_color );
53 24451736 : wide = false;
54 24451736 : fallback = false;
55 24451736 : wrap = false;
56 24179896 : }
57 :
58 14030 : void DrawState::reinitialize_tabs( unsigned int start )
59 : {
60 14030 : assert( default_tabs );
61 980308 : for ( unsigned int i = start; i < tabs.size(); i++ ) {
62 966278 : tabs[ i ] = ( (i % 8) == 0 );
63 : }
64 14030 : }
65 :
66 13446 : DrawState::DrawState( int s_width, int s_height )
67 13446 : : width( s_width ), height( s_height ),
68 13446 : cursor_col( 0 ), cursor_row( 0 ),
69 13446 : combining_char_col( 0 ), combining_char_row( 0 ), default_tabs( true ), tabs( s_width ),
70 13446 : scrolling_region_top_row( 0 ), scrolling_region_bottom_row( height - 1 ),
71 13446 : renditions( 0 ), save(),
72 13446 : next_print_will_wrap( false ), origin_mode( false ), auto_wrap_mode( true ),
73 13446 : insert_mode( false ), cursor_visible( true ), reverse_video( false ),
74 13446 : bracketed_paste( false ), mouse_reporting_mode( MOUSE_REPORTING_NONE ), mouse_focus_event( false ),
75 13446 : mouse_alternate_scroll( false ), mouse_encoding_mode( MOUSE_ENCODING_DEFAULT ), application_mode_cursor_keys( false )
76 : {
77 13446 : reinitialize_tabs( 0 );
78 13446 : }
79 :
80 13446 : Framebuffer::Framebuffer( int s_width, int s_height )
81 13446 : : rows(), icon_name(), window_title(), clipboard(), bell_count( 0 ), title_initialized( false ), ds( s_width, s_height )
82 : {
83 13446 : assert( s_height > 0 );
84 13446 : assert( s_width > 0 );
85 13446 : const size_t w = s_width;
86 13446 : const color_type c = 0;
87 26892 : rows = rows_type(s_height, row_pointer(make_shared<Row>( w, c )));
88 13446 : }
89 :
90 20841 : Framebuffer::Framebuffer( const Framebuffer &other )
91 20841 : : rows( other.rows ), icon_name( other.icon_name ), window_title( other.window_title ),
92 20841 : clipboard( other.clipboard ), bell_count( other.bell_count ),
93 20841 : title_initialized( other.title_initialized ), ds( other.ds )
94 : {
95 20841 : }
96 :
97 37121 : Framebuffer & Framebuffer::operator=( const Framebuffer &other )
98 : {
99 37121 : if ( this != &other ) {
100 37121 : rows = other.rows;
101 37121 : icon_name = other.icon_name;
102 37121 : window_title = other.window_title;
103 37121 : clipboard = other.clipboard;
104 37121 : bell_count = other.bell_count;
105 37121 : title_initialized = other.title_initialized;
106 37121 : ds = other.ds;
107 : }
108 37121 : return *this;
109 : }
110 :
111 23864531 : void Framebuffer::scroll( int N )
112 : {
113 23864531 : if ( N >= 0 ) {
114 23864529 : delete_line( ds.get_scrolling_region_top_row(), N );
115 : } else {
116 2 : insert_line( ds.get_scrolling_region_top_row(), -N );
117 : }
118 23864531 : }
119 :
120 95776485 : void DrawState::new_grapheme( void )
121 : {
122 95776485 : combining_char_col = cursor_col;
123 95776485 : combining_char_row = cursor_row;
124 24028346 : }
125 :
126 95777069 : void DrawState::snap_cursor_to_border( void )
127 : {
128 95777069 : if ( cursor_row < limit_top() ) cursor_row = limit_top();
129 95777069 : if ( cursor_row > limit_bottom() ) cursor_row = limit_bottom();
130 95777069 : if ( cursor_col < 0 ) cursor_col = 0;
131 95777069 : if ( cursor_col >= width ) cursor_col = width - 1;
132 95777069 : }
133 :
134 47806847 : void DrawState::move_row( int N, bool relative )
135 : {
136 47806847 : if ( relative ) {
137 47802078 : cursor_row += N;
138 : } else {
139 4769 : cursor_row = N + limit_top();
140 : }
141 :
142 47806847 : snap_cursor_to_border();
143 47806847 : new_grapheme();
144 47806847 : next_print_will_wrap = false;
145 47806847 : }
146 :
147 47969638 : void DrawState::move_col( int N, bool relative, bool implicit )
148 : {
149 47969638 : if ( implicit ) {
150 24028346 : new_grapheme();
151 : }
152 :
153 47969638 : if ( relative ) {
154 24028440 : cursor_col += N;
155 : } else {
156 23941198 : cursor_col = N;
157 : }
158 :
159 47969638 : if ( implicit ) {
160 24028346 : next_print_will_wrap = (cursor_col >= width);
161 : }
162 :
163 47969638 : snap_cursor_to_border();
164 47969638 : if ( !implicit ) {
165 23941292 : new_grapheme();
166 23941292 : next_print_will_wrap = false;
167 : }
168 47969638 : }
169 :
170 23937551 : void Framebuffer::move_rows_autoscroll( int rows )
171 : {
172 : /* don't scroll if outside the scrolling region */
173 23937551 : if ( (ds.get_cursor_row() < ds.get_scrolling_region_top_row())
174 23937551 : || (ds.get_cursor_row() > ds.get_scrolling_region_bottom_row()) ) {
175 0 : ds.move_row( rows, true );
176 0 : return;
177 : }
178 :
179 23937551 : if ( ds.get_cursor_row() + rows > ds.get_scrolling_region_bottom_row() ) {
180 23864527 : int N = ds.get_cursor_row() + rows - ds.get_scrolling_region_bottom_row();
181 23864527 : scroll( N );
182 23864527 : ds.move_row( -N, true );
183 73024 : } else if ( ds.get_cursor_row() + rows < ds.get_scrolling_region_top_row() ) {
184 0 : int N = ds.get_cursor_row() + rows - ds.get_scrolling_region_top_row();
185 0 : scroll( N );
186 0 : ds.move_row( -N, true );
187 : }
188 :
189 23937551 : ds.move_row( rows, true );
190 : }
191 :
192 12 : Cell *Framebuffer::get_combining_cell( void )
193 : {
194 12 : if ( (ds.get_combining_char_col() < 0)
195 12 : || (ds.get_combining_char_row() < 0)
196 12 : || (ds.get_combining_char_col() >= ds.get_width())
197 24 : || (ds.get_combining_char_row() >= ds.get_height()) ) {
198 : return NULL;
199 : } /* can happen if a resize came in between */
200 :
201 12 : return get_mutable_cell( ds.get_combining_char_row(), ds.get_combining_char_col() );
202 : }
203 :
204 0 : void DrawState::set_tab( void )
205 : {
206 0 : tabs[ cursor_col ] = true;
207 0 : }
208 :
209 0 : void DrawState::clear_tab( int col )
210 : {
211 0 : tabs[ col ] = false;
212 0 : }
213 :
214 10 : int DrawState::get_next_tab( int count ) const
215 : {
216 10 : if ( count >= 0 ) {
217 168 : for ( int i = cursor_col + 1; i < width; i++ ) {
218 166 : if ( tabs[ i ] && --count == 0 ) {
219 2 : return i;
220 : }
221 : }
222 : return -1;
223 : }
224 56 : for ( int i = cursor_col - 1; i > 0; i-- ) {
225 52 : if ( tabs[ i ] && ++count == 0 ) {
226 2 : return i;
227 : }
228 : }
229 : return 0;
230 : }
231 :
232 144 : void DrawState::set_scrolling_region( int top, int bottom )
233 : {
234 144 : if ( height < 1 ) {
235 : return;
236 : }
237 :
238 144 : scrolling_region_top_row = top;
239 144 : scrolling_region_bottom_row = bottom;
240 :
241 144 : if ( scrolling_region_top_row < 0 ) scrolling_region_top_row = 0;
242 144 : if ( scrolling_region_bottom_row >= height ) scrolling_region_bottom_row = height - 1;
243 :
244 144 : if ( scrolling_region_bottom_row < scrolling_region_top_row )
245 0 : scrolling_region_bottom_row = scrolling_region_top_row;
246 : /* real rule requires TWO-line scrolling region */
247 :
248 144 : if ( origin_mode ) {
249 0 : snap_cursor_to_border();
250 0 : new_grapheme();
251 : }
252 : }
253 :
254 95781838 : int DrawState::limit_top( void ) const
255 : {
256 95781838 : return origin_mode ? scrolling_region_top_row : 0;
257 : }
258 :
259 95777069 : int DrawState::limit_bottom( void ) const
260 : {
261 95777069 : return origin_mode ? scrolling_region_bottom_row : height - 1;
262 : }
263 :
264 24028342 : void Framebuffer::apply_renditions_to_cell( Cell *cell )
265 : {
266 24028342 : if (!cell) {
267 0 : cell = get_mutable_cell();
268 : }
269 24028342 : cell->set_renditions( ds.get_renditions() );
270 24028342 : }
271 :
272 13446 : SavedCursor::SavedCursor()
273 13446 : : cursor_col( 0 ), cursor_row( 0 ),
274 13446 : renditions( 0 ),
275 13446 : auto_wrap_mode( true ),
276 13446 : origin_mode( false )
277 0 : {}
278 :
279 0 : void DrawState::save_cursor( void )
280 : {
281 0 : save.cursor_col = cursor_col;
282 0 : save.cursor_row = cursor_row;
283 0 : save.renditions = renditions;
284 0 : save.auto_wrap_mode = auto_wrap_mode;
285 0 : save.origin_mode = origin_mode;
286 0 : }
287 :
288 0 : void DrawState::restore_cursor( void )
289 : {
290 0 : cursor_col = save.cursor_col;
291 0 : cursor_row = save.cursor_row;
292 0 : renditions = save.renditions;
293 0 : auto_wrap_mode = save.auto_wrap_mode;
294 0 : origin_mode = save.origin_mode;
295 :
296 0 : snap_cursor_to_border(); /* we could have resized in between */
297 0 : new_grapheme();
298 0 : }
299 :
300 18 : void Framebuffer::insert_line( int before_row, int count )
301 : {
302 18 : if ( (before_row < ds.get_scrolling_region_top_row())
303 18 : || (before_row > ds.get_scrolling_region_bottom_row() + 1) ) {
304 18 : return;
305 : }
306 :
307 18 : int scroll = ds.get_scrolling_region_bottom_row() + 1 - before_row;
308 18 : if ( count < scroll ) {
309 : scroll = count;
310 : }
311 :
312 18 : if ( scroll == 0 ) {
313 : return;
314 : }
315 :
316 : // delete old rows
317 18 : rows_type::iterator start = rows.begin() + ds.get_scrolling_region_bottom_row() + 1 - scroll;
318 18 : rows.erase( start, start + scroll );
319 : // insert new rows
320 18 : start = rows.begin() + before_row;
321 36 : rows.insert( start, scroll, newrow());
322 : }
323 :
324 23864545 : void Framebuffer::delete_line( int row, int count )
325 : {
326 23864545 : if ( (row < ds.get_scrolling_region_top_row())
327 23864545 : || (row > ds.get_scrolling_region_bottom_row()) ) {
328 23864545 : return;
329 : }
330 :
331 23864545 : int scroll = ds.get_scrolling_region_bottom_row() + 1 - row;
332 23864545 : if ( count < scroll ) {
333 : scroll = count;
334 : }
335 :
336 23864545 : if ( scroll == 0 ) {
337 : return;
338 : }
339 :
340 : // delete old rows
341 23864545 : rows_type::iterator start = rows.begin() + row;
342 23864545 : rows.erase( start, start + scroll );
343 : // insert a block of dummy rows
344 23864545 : start = rows.begin() + ds.get_scrolling_region_bottom_row() + 1 - scroll;
345 47729090 : rows.insert( start, scroll, newrow());
346 : }
347 :
348 23880105 : Row::Row( const size_t s_width, const color_type background_color )
349 23880105 : : cells( s_width, Cell( background_color ) ), gen( get_gen() )
350 23880105 : {}
351 :
352 23884559 : uint64_t Row::get_gen() const
353 : {
354 23884559 : static uint64_t gen_counter = 0;
355 23880105 : return gen_counter++;
356 : }
357 :
358 0 : void Row::insert_cell( int col, color_type background_color )
359 : {
360 0 : cells.insert( cells.begin() + col, Cell( background_color ) );
361 0 : cells.pop_back();
362 0 : }
363 :
364 0 : void Row::delete_cell( int col, color_type background_color )
365 : {
366 0 : cells.push_back( Cell( background_color ) );
367 0 : cells.erase( cells.begin() + col );
368 0 : }
369 :
370 0 : void Framebuffer::insert_cell( int row, int col )
371 : {
372 0 : get_mutable_row( row )->insert_cell( col, ds.get_background_rendition() );
373 0 : }
374 :
375 0 : void Framebuffer::delete_cell( int row, int col )
376 : {
377 0 : get_mutable_row( row )->delete_cell( col, ds.get_background_rendition() );
378 0 : }
379 :
380 0 : void Framebuffer::reset( void )
381 : {
382 0 : int width = ds.get_width(), height = ds.get_height();
383 0 : ds = DrawState( width, height );
384 0 : rows = rows_type( height, newrow() );
385 0 : window_title.clear();
386 0 : clipboard.clear();
387 : /* do not reset bell_count */
388 0 : }
389 :
390 0 : void Framebuffer::soft_reset( void )
391 : {
392 0 : ds.insert_mode = false;
393 0 : ds.origin_mode = false;
394 0 : ds.cursor_visible = true; /* per xterm and gnome-terminal */
395 0 : ds.application_mode_cursor_keys = false;
396 0 : ds.set_scrolling_region( 0, ds.get_height() - 1 );
397 0 : ds.add_rendition( 0 );
398 0 : ds.clear_saved_cursor();
399 0 : }
400 :
401 584 : void Framebuffer::resize( int s_width, int s_height )
402 : {
403 584 : assert( s_width > 0 );
404 584 : assert( s_height > 0 );
405 :
406 584 : int oldheight = ds.get_height();
407 584 : int oldwidth = ds.get_width();
408 584 : ds.resize( s_width, s_height );
409 :
410 584 : row_pointer blankrow( newrow());
411 584 : if ( oldheight != s_height ) {
412 66 : rows.resize( s_height, blankrow );
413 : }
414 584 : if (oldwidth == s_width) {
415 518 : return;
416 : }
417 66 : for ( rows_type::iterator i = rows.begin();
418 1584 : i != rows.end() && *i != blankrow;
419 1650 : i++ ) {
420 1584 : *i = make_shared<Row>( **i );
421 1584 : (*i)->set_wrap( false );
422 3168 : (*i)->cells.resize( s_width, Cell( ds.get_background_rendition() ) );
423 : }
424 584 : }
425 :
426 584 : void DrawState::resize( int s_width, int s_height )
427 : {
428 584 : if ( (width != s_width)
429 518 : || (height != s_height) ) {
430 : /* reset entire scrolling region on any resize */
431 : /* xterm and rxvt-unicode do this. gnome-terminal only
432 : resets scrolling region if it has to become smaller in resize */
433 132 : scrolling_region_top_row = 0;
434 132 : scrolling_region_bottom_row = s_height - 1;
435 : }
436 :
437 584 : tabs.resize( s_width );
438 584 : if ( default_tabs ) {
439 584 : reinitialize_tabs( width );
440 : }
441 :
442 584 : width = s_width;
443 584 : height = s_height;
444 :
445 584 : snap_cursor_to_border();
446 :
447 : /* saved cursor will be snapped to border on restore */
448 :
449 : /* invalidate combining char cell if necessary */
450 584 : if ( (combining_char_col >= width)
451 584 : || (combining_char_row >= height) ) {
452 36 : combining_char_col = combining_char_row = -1;
453 : }
454 584 : }
455 :
456 48374274 : Renditions::Renditions( color_type s_background )
457 48374274 : : foreground_color( 0 ), background_color( s_background ),
458 23895135 : attributes( 0 )
459 25099 : {}
460 :
461 : /* This routine cannot be used to set a color beyond the 16-color set. */
462 14918 : void Renditions::set_rendition( color_type num )
463 : {
464 14918 : if ( num == 0 ) {
465 10550 : clear_attributes();
466 10550 : foreground_color = background_color = 0;
467 10550 : return;
468 : }
469 :
470 : if ( num == 39 ) {
471 2 : foreground_color = 0;
472 2 : return;
473 : } else if ( num == 49 ) {
474 2 : background_color = 0;
475 2 : return;
476 : }
477 :
478 : if ( (30 <= num) && (num <= 37) ) { /* foreground color in 8-color set */
479 80 : foreground_color = num;
480 80 : return;
481 : } else if ( (40 <= num) && (num <= 47) ) { /* background color in 8-color set */
482 94 : background_color = num;
483 94 : return;
484 : } else if ( (90 <= num) && (num <= 97) ) { /* foreground color in 16-color set */
485 0 : foreground_color = num - 90 + 38;
486 0 : return;
487 : } else if ( (100 <= num) && (num <= 107) ) { /* background color in 16-color set */
488 0 : background_color = num - 100 + 48;
489 0 : return;
490 : }
491 :
492 4190 : bool value = num < 9;
493 4190 : switch ( num ) {
494 930 : case 1: case 22: set_attribute(bold, value); break;
495 924 : case 3: case 23: set_attribute(italic, value); break;
496 930 : case 4: case 24: set_attribute(underlined, value); break;
497 468 : case 5: case 25: set_attribute(blink, value); break;
498 476 : case 7: case 27: set_attribute(inverse, value); break;
499 462 : case 8: case 28: set_attribute(invisible, value); break;
500 : default: break; /* ignore unknown rendition */
501 : }
502 : }
503 :
504 5200 : void Renditions::set_foreground_color( int num )
505 : {
506 5200 : if ( (0 <= num) && (num <= 255) ) {
507 1504 : foreground_color = 30 + num;
508 3696 : } else if ( is_true_color( num ) ) {
509 3696 : foreground_color = num;
510 : }
511 5200 : }
512 :
513 5212 : void Renditions::set_background_color( int num )
514 : {
515 5212 : if ( (0 <= num) && (num <= 255) ) {
516 1510 : background_color = 40 + num;
517 3702 : } else if ( is_true_color( num ) ) {
518 3702 : background_color = num;
519 : }
520 5212 : }
521 :
522 31886 : std::string Renditions::sgr( void ) const
523 : {
524 31886 : std::string ret;
525 31886 : char col[64];
526 :
527 31886 : ret.append( "\033[0" );
528 31886 : if ( get_attribute( bold ) ) ret.append( ";1" );
529 31886 : if ( get_attribute( italic ) ) ret.append( ";3" );
530 31886 : if ( get_attribute( underlined ) ) ret.append( ";4" );
531 31886 : if ( get_attribute( blink ) ) ret.append( ";5" );
532 31886 : if ( get_attribute( inverse ) ) ret.append( ";7" );
533 31886 : if ( get_attribute( invisible ) ) ret.append( ";8" );
534 :
535 31886 : if ( foreground_color ) {
536 14734 : if ( is_true_color( foreground_color ) ) {
537 24590 : snprintf( col, sizeof( col ), ";38;2;%u;%u;%u",
538 9856 : (foreground_color >> 16) & 0xff,
539 9856 : (foreground_color >> 8) & 0xff,
540 9856 : foreground_color & 0xff);
541 4878 : } else if ( foreground_color > 37 ) { /* use 256-color set */
542 4598 : snprintf( col, sizeof( col ), ";38;5;%u", foreground_color - 30 );
543 : } else { /* ANSI foreground color */
544 280 : snprintf( col, sizeof( col ), ";%u", static_cast<unsigned int>( foreground_color ) );
545 : }
546 14734 : ret.append( col );
547 : }
548 31886 : if ( background_color ) {
549 14827 : if ( is_true_color( background_color ) ) {
550 24700 : snprintf( col, sizeof( col ), ";48;2;%u;%u;%u",
551 9873 : (background_color >> 16) & 0xff,
552 9873 : (background_color >> 8) & 0xff,
553 9873 : background_color & 0xff);
554 4954 : } else if ( background_color > 47 ) { /* use 256-color set */
555 4615 : snprintf( col, sizeof( col ), ";48;5;%u", background_color - 40 );
556 : } else { /* ANSI background color */
557 339 : snprintf( col, sizeof( col ), ";%u", static_cast<unsigned int>( background_color ) );
558 : }
559 14827 : ret.append( col );
560 : }
561 31886 : ret.append( "m" );
562 :
563 31886 : return ret;
564 0 : }
565 :
566 4454 : void Row::reset( color_type background_color )
567 : {
568 4454 : gen = get_gen();
569 276294 : for ( cells_type::iterator i = cells.begin();
570 276294 : i != cells.end();
571 276294 : i++ ) {
572 271840 : i->reset( background_color );
573 : }
574 4454 : }
575 :
576 6536 : void Framebuffer::prefix_window_title( const title_type &s )
577 : {
578 6536 : if ( icon_name == window_title ) {
579 : /* preserve equivalence */
580 6536 : icon_name.insert(icon_name.begin(), s.begin(), s.end() );
581 : }
582 6536 : window_title.insert(window_title.begin(), s.begin(), s.end() );
583 6536 : }
584 :
585 8 : std::string Cell::debug_contents( void ) const
586 : {
587 8 : if ( contents.empty() ) {
588 0 : return "'_' ()";
589 : }
590 8 : std::string chars( 1, '\'' );
591 8 : print_grapheme( chars );
592 8 : chars.append( "' [" );
593 8 : const char *lazycomma = "";
594 8 : char buf[64];
595 8 : for ( content_type::const_iterator i = contents.begin();
596 32 : i < contents.end();
597 32 : i++ ) {
598 :
599 24 : snprintf( buf, sizeof buf, "%s0x%02x", lazycomma, static_cast<uint8_t>(*i) );
600 24 : chars.append( buf );
601 24 : lazycomma = ", ";
602 : }
603 8 : chars.append( "]" );
604 16 : return chars;
605 8 : }
606 :
607 10256000 : bool Cell::compare( const Cell &other ) const
608 : {
609 10256000 : bool ret = false;
610 :
611 10256000 : std::string grapheme, other_grapheme;
612 :
613 10256000 : print_grapheme( grapheme );
614 10256000 : other.print_grapheme( other_grapheme );
615 :
616 10256000 : if ( grapheme != other_grapheme ) {
617 0 : ret = true;
618 0 : fprintf( stderr, "Graphemes: '%s' vs. '%s'\n",
619 : grapheme.c_str(), other_grapheme.c_str() );
620 : }
621 :
622 10256000 : if ( !contents_match( other ) ) {
623 : // ret = true;
624 8 : fprintf( stderr, "Contents: %s (%ld) vs. %s (%ld)\n",
625 8 : debug_contents().c_str(),
626 4 : static_cast<long int>( contents.size() ),
627 8 : other.debug_contents().c_str(),
628 4 : static_cast<long int>( other.contents.size() ) );
629 : }
630 :
631 10256000 : if ( fallback != other.fallback ) {
632 : // ret = true;
633 10256004 : fprintf( stderr, "fallback: %d vs. %d\n",
634 4 : fallback, other.fallback );
635 : }
636 :
637 10256000 : if ( wide != other.wide ) {
638 0 : ret = true;
639 10256000 : fprintf( stderr, "width: %d vs. %d\n",
640 0 : wide, other.wide );
641 : }
642 :
643 10256000 : if ( !(renditions == other.renditions) ) {
644 0 : ret = true;
645 0 : fprintf( stderr, "renditions differ\n" );
646 : }
647 :
648 10256000 : if ( wrap != other.wrap ) {
649 0 : ret = true;
650 10256000 : fprintf( stderr, "wrap: %d vs. %d\n",
651 0 : wrap, other.wrap );
652 : }
653 :
654 10256000 : return ret;
655 10256000 : }
|