+vector<string> EffectChain::get_labels_for_edge(const Node *from, const Node *to)
+{
+ vector<string> labels;
+
+ if (to != NULL && to->effect->needs_texture_bounce()) {
+ labels.push_back("needs_bounce");
+ }
+ if (from->effect->changes_output_size()) {
+ labels.push_back("resize");
+ }
+
+ switch (from->output_color_space) {
+ case COLORSPACE_INVALID:
+ labels.push_back("spc[invalid]");
+ break;
+ case COLORSPACE_REC_601_525:
+ labels.push_back("spc[rec601-525]");
+ break;
+ case COLORSPACE_REC_601_625:
+ labels.push_back("spc[rec601-625]");
+ break;
+ default:
+ break;
+ }
+
+ switch (from->output_gamma_curve) {
+ case GAMMA_INVALID:
+ labels.push_back("gamma[invalid]");
+ break;
+ case GAMMA_sRGB:
+ labels.push_back("gamma[sRGB]");
+ break;
+ case GAMMA_REC_601: // and GAMMA_REC_709
+ labels.push_back("gamma[rec601/709]");
+ break;
+ default:
+ break;
+ }
+
+ switch (from->output_alpha_type) {
+ case ALPHA_INVALID:
+ labels.push_back("alpha[invalid]");
+ break;
+ case ALPHA_BLANK:
+ labels.push_back("alpha[blank]");
+ break;
+ case ALPHA_POSTMULTIPLIED:
+ labels.push_back("alpha[postmult]");
+ break;
+ default:
+ break;
+ }
+
+ return labels;
+}
+
+void EffectChain::output_dot_edge(FILE *fp,
+ const string &from_node_id,
+ const string &to_node_id,
+ const vector<string> &labels)
+{
+ if (labels.empty()) {
+ fprintf(fp, " %s -> %s;\n", from_node_id.c_str(), to_node_id.c_str());
+ } else {
+ string label = labels[0];
+ for (unsigned k = 1; k < labels.size(); ++k) {
+ label += ", " + labels[k];
+ }
+ fprintf(fp, " %s -> %s [label=\"%s\"];\n", from_node_id.c_str(), to_node_id.c_str(), label.c_str());
+ }
+}
+
+void EffectChain::size_rectangle_to_fit(unsigned width, unsigned height, unsigned *output_width, unsigned *output_height)