text: /* Copyright (C) 2001-2017 Peter Selinger.
     This file is part of Potrace. It is free software and it is covered
     by the GNU General Public License. See the file COPYING for details. */
  
  /* operations on potrace_progress_t objects, which are defined in
     potracelib.h. Note: the code attempts to minimize runtime overhead
     when no progress monitoring was requested. It also tries to
     minimize excessive progress calculations beneath the "epsilon"
     threshold. */
  
  #ifndef PROGRESS_H
  #define PROGRESS_H
  
  /* structure to hold progress bar callback data */
  struct progress_s {
    void (*callback)(double progress, void *privdata); /* callback fn */
    void *data;          /* callback function's private data */
    double min, max;     /* desired range of progress, e.g. 0.0 to 1.0 */
    double epsilon;      /* granularity: can skip smaller increments */
    double b;            /* upper limit of subrange in superrange units */
    double d_prev;       /* previous value of d */
  };
  typedef struct progress_s progress_t;
  
  /* notify given progress object of current progress. Note that d is
     given in the 0.0-1.0 range, which will be scaled and translated to
     the progress object's range. */
  static inline void progress_update(double d, progress_t *prog) {
    double d_scaled;
  
    if (prog != NULL && prog->callback != NULL) {
      d_scaled = prog->min * (1-d) + prog->max * d;
      if (d == 1.0 || d_scaled >= prog->d_prev + prog->epsilon) {
        prog->callback(prog->min * (1-d) + prog->max * d, prog->data);
        prog->d_prev = d_scaled;
      }
    }
  }
  
  /* start a subrange of the given progress object. The range is
     narrowed to [a..b], relative to 0.0-1.0 coordinates. If new range
     is below granularity threshold, disable further subdivisions. */
  static inline void progress_subrange_start(double a, double b, const progress_t *prog, progress_t *sub) {
    double min, max;
  
    if (prog == NULL || prog->callback == NULL) {
      sub->callback = NULL;
      return;
    }
  
    min = prog->min * (1-a) + prog->max * a;
    max = prog->min * (1-b) + prog->max * b;
  
    if (max - min < prog->epsilon) {
      sub->callback = NULL;    /* no further progress info in subrange */
      sub->b = b;
      return;
    }
    sub->callback = prog->callback;
    sub->data = prog->data;
    sub->epsilon = prog->epsilon;
    sub->min = min;
    sub->max = max;
    sub->d_prev = prog->d_prev;
    return;
  }
  
  static inline void progress_subrange_end(progress_t *prog, progress_t *sub) {
    if (prog != NULL && prog->callback != NULL) {
      if (sub->callback == NULL) {
        progress_update(sub->b, prog);
      } else {
        prog->d_prev = sub->d_prev;
      }
    }    
  }
  
  #endif /* PROGRESS_H */
  
  