Esempio n. 1
0
/** 
 * Cuts the coverage a in 2 parts.
 *
 * over will receive the parts where coverage > tresh, while the present
 * FloatLigne will receive the parts where coverage <= tresh.
 */
void FloatLigne::Split(FloatLigne *a, float tresh, FloatLigne *over)
{
    Reset();
    if ( a->runs.empty() ) {
        return;
    }

    for (int i = 0; i < int(a->runs.size()); i++) {
        float_ligne_run runA = a->runs[i];
        if ( runA.vst >= tresh ) {
            if ( runA.ven >= tresh ) {
                if ( over ) {
                    over->AddRun(runA.st, runA.en, runA.vst, runA.ven);
                }
            } else {
                float cutPos = (runA.st * (tresh - runA.ven) + runA.en * (runA.vst - tresh)) / (runA.vst - runA.ven);
                if ( over ) {
                    over->AddRun(runA.st, cutPos, runA.vst, tresh);
                }
                AddRun(cutPos, runA.en, tresh, runA.ven);
            }
        } else {
            if ( runA.ven >= tresh ) {
                float cutPos = (runA.st * (runA.ven - tresh) + runA.en * (tresh-runA.vst)) / (runA.ven - runA.vst);
                AddRun(runA.st, cutPos, runA.vst, tresh);
                if ( over ) {
                    over->AddRun(cutPos, runA.en, tresh, runA.ven);
                }
            } else {
                AddRun(runA.st, runA.en, runA.vst, runA.ven);
            }
        }
    }
}
Esempio n. 2
0
    // Verify that text-related properties are captured in run paints.
    static void TestPaintProps(skiatest::Reporter* reporter) {
        SkFont font;
        // Kitchen sink font.
        font.setSize(42);
        font.setScaleX(4.2f);
        font.setTypeface(ToolUtils::create_portable_typeface());
        font.setSkewX(0.42f);
        font.setHinting(SkFontHinting::kFull);
        font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
        font.setEmbolden(true);
        font.setLinearMetrics(true);
        font.setSubpixel(true);
        font.setEmbeddedBitmaps(true);
        font.setForceAutoHinting(true);

        // Ensure we didn't pick default values by mistake.
        SkFont defaultFont;
        REPORTER_ASSERT(reporter, defaultFont.getSize() != font.getSize());
        REPORTER_ASSERT(reporter, defaultFont.getScaleX() != font.getScaleX());
        REPORTER_ASSERT(reporter, defaultFont.getTypefaceOrDefault() != font.getTypefaceOrDefault());
        REPORTER_ASSERT(reporter, defaultFont.getSkewX() != font.getSkewX());
        REPORTER_ASSERT(reporter, defaultFont.getHinting() != font.getHinting());
        REPORTER_ASSERT(reporter, defaultFont.getEdging() != font.getEdging());
        REPORTER_ASSERT(reporter, defaultFont.isEmbolden() != font.isEmbolden());
        REPORTER_ASSERT(reporter, defaultFont.isLinearMetrics() != font.isLinearMetrics());
        REPORTER_ASSERT(reporter, defaultFont.isSubpixel() != font.isSubpixel());
        REPORTER_ASSERT(reporter,
                        defaultFont.isEmbeddedBitmaps() != font.isEmbeddedBitmaps());
        REPORTER_ASSERT(reporter, defaultFont.isForceAutoHinting() != font.isForceAutoHinting());

        SkTextBlobBuilder builder;
        AddRun(font, 1, SkTextBlobRunIterator::kDefault_Positioning, SkPoint::Make(0, 0), builder);
        AddRun(font, 1, SkTextBlobRunIterator::kHorizontal_Positioning, SkPoint::Make(0, 0),
               builder);
        AddRun(font, 1, SkTextBlobRunIterator::kFull_Positioning, SkPoint::Make(0, 0), builder);
        sk_sp<SkTextBlob> blob(builder.make());

        SkTextBlobRunIterator it(blob.get());
        while (!it.done()) {
            REPORTER_ASSERT(reporter, it.font() == font);
            it.next();
        }

    }
Esempio n. 3
0
/*
 * Segment a paragraph into runs
 */
static int ItemizeParagraph( filter_t *p_filter, paragraph_t *p_paragraph )
{
    if( p_paragraph->i_size <= 0 )
    {
        msg_Err( p_filter,
                 "ItemizeParagraph() invalid parameters. Paragraph size: %d",
                 p_paragraph->i_size );
        return VLC_EGENERIC;
    }

    int i_last_run_start = 0;
    text_style_t *p_last_style = p_paragraph->pp_styles[ 0 ];

#ifdef HAVE_HARFBUZZ
    hb_script_t last_script = p_paragraph->p_scripts[ 0 ];
    FriBidiLevel last_level = p_paragraph->p_levels[ 0 ];
#endif

    for( int i = 0; i <= p_paragraph->i_size; ++i )
    {
        if( i == p_paragraph->i_size
#ifdef HAVE_HARFBUZZ
            || last_script != p_paragraph->p_scripts[ i ]
            || last_level != p_paragraph->p_levels[ i ]
#endif
            || p_last_style->i_font_size != p_paragraph->pp_styles[ i ]->i_font_size
            || ( ( p_last_style->i_style_flags
                 ^ p_paragraph->pp_styles[ i ]->i_style_flags )
                 & STYLE_HALFWIDTH )
            ||!FaceStyleEquals( p_last_style, p_paragraph->pp_styles[ i ] ) )
        {
            int i_ret = AddRun( p_filter, p_paragraph, i_last_run_start, i, 0 );
            if( i_ret )
                return i_ret;

            if( i < p_paragraph->i_size )
            {
                i_last_run_start = i;
                p_last_style = p_paragraph->pp_styles[ i ];
#ifdef HAVE_HARFBUZZ
                last_script = p_paragraph->p_scripts[ i ];
                last_level = p_paragraph->p_levels[ i ];
#endif
            }
        }
    }
    return VLC_SUCCESS;
}
Esempio n. 4
0
    static void RunBuilderTest(skiatest::Reporter* reporter, SkTextBlobBuilder& builder,
                               const RunDef in[], unsigned inCount,
                               const RunDef out[], unsigned outCount) {
        SkFont font;

        unsigned glyphCount = 0;
        unsigned posCount = 0;

        for (unsigned i = 0; i < inCount; ++i) {
            AddRun(font, in[i].count, in[i].pos, SkPoint::Make(in[i].x, in[i].y), builder);
            glyphCount += in[i].count;
            posCount += in[i].count * in[i].pos;
        }

        sk_sp<SkTextBlob> blob(builder.make());
        REPORTER_ASSERT(reporter, (inCount > 0) == SkToBool(blob));
        if (!blob) {
            return;
        }

        SkTextBlobRunIterator it(blob.get());
        for (unsigned i = 0; i < outCount; ++i) {
            REPORTER_ASSERT(reporter, !it.done());
            REPORTER_ASSERT(reporter, out[i].pos == it.positioning());
            REPORTER_ASSERT(reporter, out[i].count == it.glyphCount());
            if (SkTextBlobRunIterator::kDefault_Positioning == out[i].pos) {
                REPORTER_ASSERT(reporter, out[i].x == it.offset().x());
                REPORTER_ASSERT(reporter, out[i].y == it.offset().y());
            } else if (SkTextBlobRunIterator::kHorizontal_Positioning == out[i].pos) {
                REPORTER_ASSERT(reporter, out[i].y == it.offset().y());
            }

            for (unsigned k = 0; k < it.glyphCount(); ++k) {
                REPORTER_ASSERT(reporter, k % 128 == it.glyphs()[k]);
                if (SkTextBlobRunIterator::kHorizontal_Positioning == it.positioning()) {
                    REPORTER_ASSERT(reporter, SkIntToScalar(k % 128) == it.pos()[k]);
                } else if (SkTextBlobRunIterator::kFull_Positioning == it.positioning()) {
                    REPORTER_ASSERT(reporter, SkIntToScalar(k % 128) == it.pos()[k * 2]);
                    REPORTER_ASSERT(reporter, -SkIntToScalar(k % 128) == it.pos()[k * 2 + 1]);
                }
            }

            it.next();
        }

        REPORTER_ASSERT(reporter, it.done());
    }
Esempio n. 5
0
/// Extract the parts where coverage > tresh.
void FloatLigne::Over(FloatLigne *a, float tresh)
{
    Reset();
    if ( a->runs.empty() ) {
        return;
    }

    bool startExists = false;
    float lastStart = 0;
    float lastEnd = 0;
    
    for (int i = 0; i < int(a->runs.size()); i++) {
        float_ligne_run runA = a->runs[i];
        if ( runA.vst >= tresh ) {
            if ( runA.ven >= tresh ) {
                if ( startExists ) {
                    if ( lastEnd >= runA.st - 0.00001 ) {
                        lastEnd = runA.en;
                    } else {
                        AddRun(lastStart, lastEnd, tresh, tresh);
                        lastStart = runA.st;
                        lastEnd = runA.en;
                    }
                } else {
                    lastStart = runA.st;
                    lastEnd = runA.en;
                }
                startExists = true;
                
            } else {
                
                float cutPos = (runA.st * (tresh - runA.ven) + runA.en * (runA.vst - tresh)) / (runA.vst - runA.ven);
                if ( startExists ) {
                    if ( lastEnd >= runA.st - 0.00001 ) {
                        AddRun(lastStart, cutPos, tresh, tresh);
                    } else {
                        AddRun(lastStart, lastEnd, tresh, tresh);
                        AddRun(runA.st, cutPos, tresh, tresh);
                    }
                } else {
                    AddRun(runA.st, cutPos, tresh, tresh);
                }
                startExists = false;
            }
            
        } else {
            if ( runA.ven >= tresh ) {
                float cutPos = (runA.st * (runA.ven - tresh) + runA.en * (tresh - runA.vst)) / (runA.ven - runA.vst);
                if ( startExists ) {
                    AddRun(lastStart, lastEnd, tresh, tresh);
                }
                startExists = true;
                lastStart = cutPos;
                lastEnd = runA.en;
            } else {
                if ( startExists ) {
                    AddRun(lastStart, lastEnd, tresh, tresh);
                }
                startExists = false;
            }
        }
    }
    
    if ( startExists ) {
        AddRun(lastStart, lastEnd, tresh, tresh);
    }
}
Esempio n. 6
0
int FloatLigne::AddRun(float st, float en, float vst, float ven)
{
    return AddRun(st, en, vst, ven, (ven - vst) / (en - st));
}
Esempio n. 7
0
/**
 * Extract a set of non-overlapping runs from the boundaries.
 *
 * We scan the boundaries left to right, maintaining a set of coverage 
 * portions currently being scanned. For each such portion, the function 
 * will add the index of its first boundary in an array; but instead of 
 * allocating another array, it uses a field in float_ligne_bord: pend_ind.
 * The outcome is that an array of float_ligne_run is produced.
 */
void FloatLigne::Flatten()
{
    if ( int(bords.size()) <= 1 ) {
        Reset();
        return;
    }
    
    runs.clear();

//	qsort(bords,bords.size(),sizeof(float_ligne_bord),FloatLigne::CmpBord);
//	SortBords(0,bords.size()-1);
  
    float totPente = 0;
    float totStart = 0;
    float totX = bords[0].pos;
    
    bool startExists = false;
    float lastStart = 0;
    float lastVal = 0;
    int pending = 0;
    
//	for (int i=0;i<bords.size();) {
    // read the list from left to right, adding a run for each boundary crossed, minus runs with alpha=0
    for (int i=/*0*/s_first; i>=0 && i < int(bords.size()) ;) {
        
        float cur = bords[i].pos;  // position of the current boundary (there may be several boundaries at this position)
        float leftV = 0;  // deltas in coverage value at this position
        float rightV = 0;
        float leftP = 0; // deltas in coverage increase per unit length at this position
        float rightP = 0;
        
        // more precisely, leftV is the sum of decreases of coverage value,
        // while rightV is the sum of increases, so that leftV+rightV is the delta.
        // idem for leftP and rightP
    
        // start by scanning all boundaries that end a portion at this position
        while ( i >= 0 && i < int(bords.size()) && bords[i].pos == cur && bords[i].start == false ) {
            leftV += bords[i].val;
            leftP += bords[i].pente;
            
#ifndef faster_flatten
            // we need to remove the boundary that started this coverage portion for the pending list
            if ( bords[i].other >= 0 && bords[i].other < int(bords.size()) ) {
                // so we use the pend_inv "array"
                int const k = bords[bords[i].other].pend_inv;
                if ( k >= 0 && k < pending ) {
                    // and update the pend_ind array and its inverse pend_inv
                    bords[k].pend_ind = bords[pending - 1].pend_ind;
                    bords[bords[k].pend_ind].pend_inv = k;
                }
            }
#endif
            
            // one less portion pending
            pending--;
            // and we move to the next boundary in the doubly linked list
            i=bords[i].s_next;
            //i++;
        }
        
        // then scan all boundaries that start a portion at this position
        while ( i >= 0 && i < int(bords.size()) && bords[i].pos == cur && bords[i].start == true ) {
            rightV += bords[i].val;
            rightP += bords[i].pente;
#ifndef faster_flatten
            bords[pending].pend_ind=i;
            bords[i].pend_inv=pending;
#endif
            pending++;
            i = bords[i].s_next;
            //i++;
        }

        // coverage value at end of the run will be "start coverage"+"delta per unit length"*"length"
        totStart = totStart + totPente * (cur - totX);
    
        if ( startExists ) {
            // add that run
            AddRun(lastStart, cur, lastVal, totStart, totPente);
        }
        // update "delta coverage per unit length"
        totPente += rightP - leftP;
        // not really needed here
        totStart += rightV - leftV;
        // update position
        totX = cur;
        if ( pending > 0 ) {
            startExists = true;
            
#ifndef faster_flatten
            // to avoid accumulation of numerical errors, we compute an accurate coverage for this position "cur"
            totStart = RemainingValAt(cur, pending);
#endif
            lastVal = totStart;
            lastStart = cur;
        } else {
            startExists = false;
            totStart = 0;
            totPente = 0;
        }
    }
}
Esempio n. 8
0
static int ShapeParagraphHarfBuzz( filter_t *p_filter,
                                   paragraph_t **p_old_paragraph )
{
    paragraph_t *p_paragraph = *p_old_paragraph;
    paragraph_t *p_new_paragraph = 0;
    filter_sys_t *p_sys = p_filter->p_sys;
    int i_total_glyphs = 0;
    int i_ret = VLC_EGENERIC;

    if( p_paragraph->i_size <= 0 || p_paragraph->i_runs_count <= 0 )
    {
        msg_Err( p_filter, "ShapeParagraphHarfBuzz() invalid parameters. "
                 "Paragraph size: %d. Runs count %d",
                 p_paragraph->i_size, p_paragraph->i_runs_count );
        return VLC_EGENERIC;
    }

    for( int i = 0; i < p_paragraph->i_runs_count; ++i )
    {
        run_desc_t *p_run = p_paragraph->p_runs + i;
        text_style_t *p_style = p_run->p_style;

        /*
         * When using HarfBuzz, this is where font faces are loaded.
         * In the other two paths (shaping with FriBidi or no
         * shaping at all), faces are loaded in LoadGlyphs()
         */
        FT_Face p_face = 0;
        if( !p_run->p_face )
        {
            p_face = LoadFace( p_filter, p_style );
            if( !p_face )
            {
                p_face = p_sys->p_face;
                p_style = &p_sys->style;
                p_run->p_style = p_style;
            }
            p_run->p_face = p_face;
        }
        else
            p_face = p_run->p_face;

        p_run->p_hb_font = hb_ft_font_create( p_face, 0 );
        if( !p_run->p_hb_font )
        {
            msg_Err( p_filter,
                     "ShapeParagraphHarfBuzz(): hb_ft_font_create() error" );
            goto error;
        }

        p_run->p_buffer = hb_buffer_create();
        if( !p_run->p_buffer )
        {
            msg_Err( p_filter,
                     "ShapeParagraphHarfBuzz(): hb_buffer_create() error" );
            goto error;
        }

        hb_buffer_set_direction( p_run->p_buffer, p_run->direction );
        hb_buffer_set_script( p_run->p_buffer, p_run->script );
#ifdef __OS2__
        hb_buffer_add_utf16( p_run->p_buffer,
                             p_paragraph->p_code_points + p_run->i_start_offset,
                             p_run->i_end_offset - p_run->i_start_offset, 0,
                             p_run->i_end_offset - p_run->i_start_offset );
#else
        hb_buffer_add_utf32( p_run->p_buffer,
                             p_paragraph->p_code_points + p_run->i_start_offset,
                             p_run->i_end_offset - p_run->i_start_offset, 0,
                             p_run->i_end_offset - p_run->i_start_offset );
#endif
        hb_shape( p_run->p_hb_font, p_run->p_buffer, 0, 0 );
        p_run->p_glyph_infos =
            hb_buffer_get_glyph_infos( p_run->p_buffer, &p_run->i_glyph_count );
        p_run->p_glyph_positions =
            hb_buffer_get_glyph_positions( p_run->p_buffer, &p_run->i_glyph_count );

        if( p_run->i_glyph_count <= 0 )
        {
            msg_Err( p_filter,
                     "ShapeParagraphHarfBuzz() invalid glyph count in shaped run" );
            goto error;
        }

        i_total_glyphs += p_run->i_glyph_count;
    }

    p_new_paragraph = NewParagraph( p_filter, i_total_glyphs, 0, 0, 0,
                                    p_paragraph->i_runs_size );
    if( !p_new_paragraph )
    {
        i_ret = VLC_ENOMEM;
        goto error;
    }
    p_new_paragraph->paragraph_type = p_paragraph->paragraph_type;

    int i_index = 0;
    for( int i = 0; i < p_paragraph->i_runs_count; ++i )
    {
        run_desc_t *p_run = p_paragraph->p_runs + i;
        hb_glyph_info_t *p_infos = p_run->p_glyph_infos;
        hb_glyph_position_t *p_positions = p_run->p_glyph_positions;
        for( unsigned int j = 0; j < p_run->i_glyph_count; ++j )
        {
            /*
             * HarfBuzz reverses the order of glyphs in RTL runs. We reverse
             * it again here to keep the glyphs in their logical order.
             * For line breaking of paragraphs to work correctly, visual
             * reordering should be done after line breaking has taken
             * place.
             */
            int i_run_index = p_run->direction == HB_DIRECTION_LTR ?
                    j : p_run->i_glyph_count - 1 - j;
            int i_source_index =
                    p_infos[ i_run_index ].cluster + p_run->i_start_offset;

            p_new_paragraph->p_code_points[ i_index ] = 0;
            p_new_paragraph->pi_glyph_indices[ i_index ] =
                p_infos[ i_run_index ].codepoint;
            p_new_paragraph->p_scripts[ i_index ] =
                p_paragraph->p_scripts[ i_source_index ];
            p_new_paragraph->p_types[ i_index ] =
                p_paragraph->p_types[ i_source_index ];
            p_new_paragraph->p_levels[ i_index ] =
                p_paragraph->p_levels[ i_source_index ];
            p_new_paragraph->pp_styles[ i_index ] =
                p_paragraph->pp_styles[ i_source_index ];
            p_new_paragraph->pi_karaoke_bar[ i_index ] =
                p_paragraph->pi_karaoke_bar[ i_source_index ];
            p_new_paragraph->p_glyph_bitmaps[ i_index ].i_x_offset =
                p_positions[ i_run_index ].x_offset;
            p_new_paragraph->p_glyph_bitmaps[ i_index ].i_y_offset =
                p_positions[ i_run_index ].y_offset;
            p_new_paragraph->p_glyph_bitmaps[ i_index ].i_x_advance =
                p_positions[ i_run_index ].x_advance;
            p_new_paragraph->p_glyph_bitmaps[ i_index ].i_y_advance =
                p_positions[ i_run_index ].y_advance;

            ++i_index;
        }
        if( AddRun( p_filter, p_new_paragraph, i_index - p_run->i_glyph_count,
                    i_index, p_run->p_face ) )
            goto error;
    }

    for( int i = 0; i < p_paragraph->i_runs_count; ++i )
    {
        hb_font_destroy( p_paragraph->p_runs[ i ].p_hb_font );
        hb_buffer_destroy( p_paragraph->p_runs[ i ].p_buffer );
    }
    FreeParagraph( *p_old_paragraph );
    *p_old_paragraph = p_new_paragraph;

    return VLC_SUCCESS;

error:
    for( int i = 0; i < p_paragraph->i_runs_count; ++i )
    {
        if( p_paragraph->p_runs[ i ].p_hb_font )
            hb_font_destroy( p_paragraph->p_runs[ i ].p_hb_font );
        if( p_paragraph->p_runs[ i ].p_buffer )
            hb_buffer_destroy( p_paragraph->p_runs[ i ].p_buffer );
    }

    if( p_new_paragraph )
        FreeParagraph( p_new_paragraph );

    return i_ret;
}
Esempio n. 9
0
// write current pattern to file using extended RLE format
const char *writerle(std::ostream &os, char *comments, lifealgo &imp,
                     int top, int left, int bottom, int right,
                     bool xrle)
{
   badwrite = false;
   if (xrle) {
      // write out #CXRLE line; note that the XRLE indicator is prefixed
      // with #C so apps like Life32 and MCell will ignore the line
      os << "#CXRLE Pos=" << left << ',' << top;
      if (imp.getGeneration() > bigint::zero)
         os << " Gen=" << imp.getGeneration().tostring('\0');
      os << '\n';
   }

   char *endcomms = NULL;
   if (comments && comments[0]) {
      // write given comment line(s) -- can't just do fputs(comments,f)
      // because comments might include arbitrary text after the "!"
      char *p = comments;
      while (*p == '#') {
         while (*p != '\n') p++;
         p++;
      }
      if (p != comments) {
         char savech = *p;
         *p = '\0';
         os << comments;
         *p = savech;
      }
      // any comment lines not starting with # will be written after "!"
      if (*p != '\0') endcomms = p;
   }

   if ( imp.isEmpty() || top > bottom || left > right ) {
      // empty pattern
      os << "x = 0, y = 0, rule = " << imp.getrule() << "\n!\n";
   } else {
      // do header line
      unsigned int wd = right - left + 1;
      unsigned int ht = bottom - top + 1;
      sprintf(outbuff, "x = %u, y = %u, rule = %s\n", wd, ht, imp.getrule());
      outpos = strlen(outbuff);

      // do RLE data
      unsigned int linelen = 0;
      unsigned int brun = 0;
      unsigned int orun = 0;
      unsigned int dollrun = 0;
      int laststate = WRLE_NONE ;
      int multistate = imp.NumCellStates() > 2 ;
      int cx, cy;
      
      // for showing accurate progress we need to add pattern height to pop count
      // in case this is a huge pattern with many blank rows
      double maxcount = imp.getPopulation().todouble() + ht;
      double accumcount = 0;
      int currcount = 0;
      int v = 0 ;
      for ( cy=top; cy<=bottom; cy++ ) {
         // set lastchar to anything except 'o' or 'b'
         laststate = WRLE_NONE ;
         currcount++;
         for ( cx=left; cx<=right; cx++ ) {
            int skip = imp.nextcell(cx, cy, v);
            if (skip + cx > right)
               skip = -1;           // pretend we found no more live cells
            if (skip > 0) {
               // have exactly "skip" dead cells here
               if (laststate == 0) {
                  brun += skip;
               } else {
                  if (orun > 0) {
                     // output current run of live cells
                     AddRun(os, laststate, multistate, orun, linelen);
                  }
                  laststate = 0 ;
                  brun = skip;
               }
            }
            if (skip >= 0) {
               // found next live cell in this row
               cx += skip;
               if (laststate == v) {
                  orun++;
               } else {
                  if (dollrun > 0)
                     // output current run of $ chars
                     AddRun(os, WRLE_NEWLINE, multistate, dollrun, linelen);
                  if (brun > 0)
                     // output current run of dead cells
                     AddRun(os, 0, multistate, brun, linelen);
                  if (orun > 0)
                     AddRun(os, laststate, multistate, orun, linelen) ;
                  laststate = v ;
                  orun = 1;
               }
               currcount++;
            } else {
               cx = right + 1;  // done this row
            }
            if (currcount > 1024) {
               char msg[128];
               accumcount += currcount;
               currcount = 0;
               sprintf(msg, "File size: %.2f MB", os.tellp() / 1048576.0);
               if (lifeabortprogress(accumcount / maxcount, msg)) break;
            }
         }
         // end of current row
         if (isaborted()) break;
         if (laststate == 0)
            // forget dead cells at end of row
            brun = 0;
         else if (laststate >= 0)
            // output current run of live cells
            AddRun(os, laststate, multistate, orun, linelen);
         dollrun++;
      }
      
      // terminate RLE data
      dollrun = 1;
      AddRun(os, WRLE_EOP, multistate, dollrun, linelen);
      putchar('\n', os);

      // flush outbuff
      if (outpos > 0 && !badwrite && !os.write(outbuff, outpos))
         badwrite = true;
   }

   if (endcomms) os << endcomms;

   if (badwrite)
      return "Failed to write output buffer!";
   else
      return 0;
}
Esempio n. 10
0
		void Paragraph::Add(const Run& run)
		{
			AddRun(run);
		}