Index: third_party/libwebp/utils/rescaler.c |
diff --git a/third_party/libwebp/utils/rescaler.c b/third_party/libwebp/utils/rescaler.c |
index 3a43229127fd52f93bc09c978640bdf1472de95a..00c9300bfbdd5009e88f87e45b9a59f158584884 100644 |
--- a/third_party/libwebp/utils/rescaler.c |
+++ b/third_party/libwebp/utils/rescaler.c |
@@ -14,451 +14,8 @@ |
#include <assert.h> |
#include <stdlib.h> |
#include <string.h> |
-#include "./rescaler.h" |
#include "../dsp/dsp.h" |
- |
-//------------------------------------------------------------------------------ |
-// Implementations of critical functions ImportRow / ExportRow |
- |
-// Import a row of data and save its contribution in the rescaler. |
-// 'channel' denotes the channel number to be imported. 'Expand' corresponds to |
-// the wrk->x_expand case. Otherwise, 'Shrink' is to be used. |
-typedef void (*WebPRescalerImportRowFunc)(WebPRescaler* const wrk, |
- const uint8_t* src); |
-static WebPRescalerImportRowFunc WebPRescalerImportRowExpand; |
-static WebPRescalerImportRowFunc WebPRescalerImportRowShrink; |
- |
-// Export one row (starting at x_out position) from rescaler. |
-// 'Expand' corresponds to the wrk->y_expand case. |
-// Otherwise 'Shrink' is to be used |
-typedef void (*WebPRescalerExportRowFunc)(WebPRescaler* const wrk); |
-static WebPRescalerExportRowFunc WebPRescalerExportRowExpand; |
-static WebPRescalerExportRowFunc WebPRescalerExportRowShrink; |
- |
-#define WEBP_RESCALER_RFIX 32 // fixed-point precision for multiplies |
-#define WEBP_RESCALER_ONE (1ull << WEBP_RESCALER_RFIX) |
-#define WEBP_RESCALER_FRAC(x, y) \ |
- ((uint32_t)(((uint64_t)(x) << WEBP_RESCALER_RFIX) / (y))) |
-#define ROUNDER (WEBP_RESCALER_ONE >> 1) |
-#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX) |
- |
-static void ImportRowExpandC(WebPRescaler* const wrk, const uint8_t* src) { |
- const int x_stride = wrk->num_channels; |
- const int x_out_max = wrk->dst_width * wrk->num_channels; |
- int channel; |
- assert(!WebPRescalerInputDone(wrk)); |
- assert(wrk->x_expand); |
- for (channel = 0; channel < x_stride; ++channel) { |
- int x_in = channel; |
- int x_out = channel; |
- // simple bilinear interpolation |
- int accum = wrk->x_add; |
- int left = src[x_in]; |
- int right = (wrk->src_width > 1) ? src[x_in + x_stride] : left; |
- x_in += x_stride; |
- while (1) { |
- wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum; |
- x_out += x_stride; |
- if (x_out >= x_out_max) break; |
- accum -= wrk->x_sub; |
- if (accum < 0) { |
- left = right; |
- x_in += x_stride; |
- assert(x_in < wrk->src_width * x_stride); |
- right = src[x_in]; |
- accum += wrk->x_add; |
- } |
- } |
- assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0); |
- } |
-} |
- |
-static void ImportRowShrinkC(WebPRescaler* const wrk, const uint8_t* src) { |
- const int x_stride = wrk->num_channels; |
- const int x_out_max = wrk->dst_width * wrk->num_channels; |
- int channel; |
- assert(!WebPRescalerInputDone(wrk)); |
- assert(!wrk->x_expand); |
- for (channel = 0; channel < x_stride; ++channel) { |
- int x_in = channel; |
- int x_out = channel; |
- uint32_t sum = 0; |
- int accum = 0; |
- while (x_out < x_out_max) { |
- uint32_t base = 0; |
- accum += wrk->x_add; |
- while (accum > 0) { |
- accum -= wrk->x_sub; |
- assert(x_in < wrk->src_width * x_stride); |
- base = src[x_in]; |
- sum += base; |
- x_in += x_stride; |
- } |
- { // Emit next horizontal pixel. |
- const rescaler_t frac = base * (-accum); |
- wrk->frow[x_out] = sum * wrk->x_sub - frac; |
- // fresh fractional start for next pixel |
- sum = (int)MULT_FIX(frac, wrk->fx_scale); |
- } |
- x_out += x_stride; |
- } |
- assert(accum == 0); |
- } |
-} |
- |
-//------------------------------------------------------------------------------ |
-// Row export |
- |
-static void ExportRowExpandC(WebPRescaler* const wrk) { |
- int x_out; |
- uint8_t* const dst = wrk->dst; |
- rescaler_t* const irow = wrk->irow; |
- const int x_out_max = wrk->dst_width * wrk->num_channels; |
- const rescaler_t* const frow = wrk->frow; |
- assert(!WebPRescalerOutputDone(wrk)); |
- assert(wrk->y_accum <= 0); |
- assert(wrk->y_expand); |
- assert(wrk->y_sub != 0); |
- if (wrk->y_accum == 0) { |
- for (x_out = 0; x_out < x_out_max; ++x_out) { |
- const uint32_t J = frow[x_out]; |
- const int v = (int)MULT_FIX(J, wrk->fy_scale); |
- assert(v >= 0 && v <= 255); |
- dst[x_out] = v; |
- } |
- } else { |
- const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); |
- const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); |
- for (x_out = 0; x_out < x_out_max; ++x_out) { |
- const uint64_t I = (uint64_t)A * frow[x_out] |
- + (uint64_t)B * irow[x_out]; |
- const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX); |
- const int v = (int)MULT_FIX(J, wrk->fy_scale); |
- assert(v >= 0 && v <= 255); |
- dst[x_out] = v; |
- } |
- } |
-} |
- |
-static void ExportRowShrinkC(WebPRescaler* const wrk) { |
- int x_out; |
- uint8_t* const dst = wrk->dst; |
- rescaler_t* const irow = wrk->irow; |
- const int x_out_max = wrk->dst_width * wrk->num_channels; |
- const rescaler_t* const frow = wrk->frow; |
- const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum); |
- assert(!WebPRescalerOutputDone(wrk)); |
- assert(wrk->y_accum <= 0); |
- assert(!wrk->y_expand); |
- if (yscale) { |
- for (x_out = 0; x_out < x_out_max; ++x_out) { |
- const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale); |
- const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale); |
- assert(v >= 0 && v <= 255); |
- dst[x_out] = v; |
- irow[x_out] = frac; // new fractional start |
- } |
- } else { |
- for (x_out = 0; x_out < x_out_max; ++x_out) { |
- const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale); |
- assert(v >= 0 && v <= 255); |
- dst[x_out] = v; |
- irow[x_out] = 0; |
- } |
- } |
-} |
- |
-//------------------------------------------------------------------------------ |
-// Main entry calls |
- |
-void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) { |
- assert(!WebPRescalerInputDone(wrk)); |
- if (!wrk->x_expand) { |
- WebPRescalerImportRowShrink(wrk, src); |
- } else { |
- WebPRescalerImportRowExpand(wrk, src); |
- } |
-} |
- |
-void WebPRescalerExportRow(WebPRescaler* const wrk) { |
- if (wrk->y_accum <= 0) { |
- assert(!WebPRescalerOutputDone(wrk)); |
- if (wrk->y_expand) { |
- WebPRescalerExportRowExpand(wrk); |
- } else if (wrk->fxy_scale) { |
- WebPRescalerExportRowShrink(wrk); |
- } else { // very special case for src = dst = 1x1 |
- int i; |
- assert(wrk->src_width == 1 && wrk->dst_width <= 2); |
- assert(wrk->src_height == 1 && wrk->dst_height == 1); |
- for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) { |
- wrk->dst[i] = wrk->irow[i]; |
- wrk->irow[i] = 0; |
- } |
- } |
- wrk->y_accum += wrk->y_add; |
- wrk->dst += wrk->dst_stride; |
- ++wrk->dst_y; |
- } |
-} |
- |
-//------------------------------------------------------------------------------ |
-// MIPS version |
- |
-#if defined(WEBP_USE_MIPS32) |
- |
-static void ImportRowShrinkMIPS(WebPRescaler* const wrk, const uint8_t* src) { |
- const int x_stride = wrk->num_channels; |
- const int x_out_max = wrk->dst_width * wrk->num_channels; |
- const int fx_scale = wrk->fx_scale; |
- const int x_add = wrk->x_add; |
- const int x_sub = wrk->x_sub; |
- const int x_stride1 = x_stride << 2; |
- int channel; |
- assert(!wrk->x_expand); |
- assert(!WebPRescalerInputDone(wrk)); |
- |
- for (channel = 0; channel < x_stride; ++channel) { |
- const uint8_t* src1 = src + channel; |
- rescaler_t* frow = wrk->frow + channel; |
- int temp1, temp2, temp3; |
- int base, frac, sum; |
- int accum, accum1; |
- int loop_c = x_out_max - channel; |
- |
- __asm__ volatile ( |
- "li %[temp1], 0x8000 \n\t" |
- "li %[temp2], 0x10000 \n\t" |
- "li %[sum], 0 \n\t" |
- "li %[accum], 0 \n\t" |
- "1: \n\t" |
- "addu %[accum], %[accum], %[x_add] \n\t" |
- "li %[base], 0 \n\t" |
- "blez %[accum], 3f \n\t" |
- "2: \n\t" |
- "lbu %[base], 0(%[src1]) \n\t" |
- "subu %[accum], %[accum], %[x_sub] \n\t" |
- "addu %[src1], %[src1], %[x_stride] \n\t" |
- "addu %[sum], %[sum], %[base] \n\t" |
- "bgtz %[accum], 2b \n\t" |
- "3: \n\t" |
- "negu %[accum1], %[accum] \n\t" |
- "mul %[frac], %[base], %[accum1] \n\t" |
- "mul %[temp3], %[sum], %[x_sub] \n\t" |
- "subu %[loop_c], %[loop_c], %[x_stride] \n\t" |
- "mult %[temp1], %[temp2] \n\t" |
- "maddu %[frac], %[fx_scale] \n\t" |
- "mfhi %[sum] \n\t" |
- "subu %[temp3], %[temp3], %[frac] \n\t" |
- "sw %[temp3], 0(%[frow]) \n\t" |
- "addu %[frow], %[frow], %[x_stride1] \n\t" |
- "bgtz %[loop_c], 1b \n\t" |
- : [accum]"=&r"(accum), [src1]"+r"(src1), [temp3]"=&r"(temp3), |
- [sum]"=&r"(sum), [base]"=&r"(base), [frac]"=&r"(frac), |
- [frow]"+r"(frow), [accum1]"=&r"(accum1), |
- [temp2]"=&r"(temp2), [temp1]"=&r"(temp1) |
- : [x_stride]"r"(x_stride), [fx_scale]"r"(fx_scale), |
- [x_sub]"r"(x_sub), [x_add]"r"(x_add), |
- [loop_c]"r"(loop_c), [x_stride1]"r"(x_stride1) |
- : "memory", "hi", "lo" |
- ); |
- assert(accum == 0); |
- } |
-} |
- |
-static void ImportRowExpandMIPS(WebPRescaler* const wrk, const uint8_t* src) { |
- const int x_stride = wrk->num_channels; |
- const int x_out_max = wrk->dst_width * wrk->num_channels; |
- const int x_add = wrk->x_add; |
- const int x_sub = wrk->x_sub; |
- const int src_width = wrk->src_width; |
- const int x_stride1 = x_stride << 2; |
- int channel; |
- assert(wrk->x_expand); |
- assert(!WebPRescalerInputDone(wrk)); |
- |
- for (channel = 0; channel < x_stride; ++channel) { |
- const uint8_t* src1 = src + channel; |
- rescaler_t* frow = wrk->frow + channel; |
- int temp1, temp2, temp3, temp4; |
- int frac; |
- int accum; |
- int x_out = channel; |
- |
- __asm__ volatile ( |
- "addiu %[temp3], %[src_width], -1 \n\t" |
- "lbu %[temp2], 0(%[src1]) \n\t" |
- "addu %[src1], %[src1], %[x_stride] \n\t" |
- "bgtz %[temp3], 0f \n\t" |
- "addiu %[temp1], %[temp2], 0 \n\t" |
- "b 3f \n\t" |
- "0: \n\t" |
- "lbu %[temp1], 0(%[src1]) \n\t" |
- "3: \n\t" |
- "addiu %[accum], %[x_add], 0 \n\t" |
- "1: \n\t" |
- "subu %[temp3], %[temp2], %[temp1] \n\t" |
- "mul %[temp3], %[temp3], %[accum] \n\t" |
- "mul %[temp4], %[temp1], %[x_add] \n\t" |
- "addu %[temp3], %[temp4], %[temp3] \n\t" |
- "sw %[temp3], 0(%[frow]) \n\t" |
- "addu %[frow], %[frow], %[x_stride1] \n\t" |
- "addu %[x_out], %[x_out], %[x_stride] \n\t" |
- "subu %[temp3], %[x_out], %[x_out_max] \n\t" |
- "bgez %[temp3], 2f \n\t" |
- "subu %[accum], %[accum], %[x_sub] \n\t" |
- "bgez %[accum], 4f \n\t" |
- "addiu %[temp2], %[temp1], 0 \n\t" |
- "addu %[src1], %[src1], %[x_stride] \n\t" |
- "lbu %[temp1], 0(%[src1]) \n\t" |
- "addu %[accum], %[accum], %[x_add] \n\t" |
- "4: \n\t" |
- "b 1b \n\t" |
- "2: \n\t" |
- : [src1]"+r"(src1), [accum]"=&r"(accum), [temp1]"=&r"(temp1), |
- [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), |
- [x_out]"+r"(x_out), [frac]"=&r"(frac), [frow]"+r"(frow) |
- : [x_stride]"r"(x_stride), [x_add]"r"(x_add), [x_sub]"r"(x_sub), |
- [x_stride1]"r"(x_stride1), [src_width]"r"(src_width), |
- [x_out_max]"r"(x_out_max) |
- : "memory", "hi", "lo" |
- ); |
- assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0); |
- } |
-} |
- |
-//------------------------------------------------------------------------------ |
-// Row export |
- |
-static void ExportRowExpandMIPS(WebPRescaler* const wrk) { |
- uint8_t* dst = wrk->dst; |
- rescaler_t* irow = wrk->irow; |
- const int x_out_max = wrk->dst_width * wrk->num_channels; |
- const rescaler_t* frow = wrk->frow; |
- int temp0, temp1, temp3, temp4, temp5, loop_end; |
- const int temp2 = (int)wrk->fy_scale; |
- const int temp6 = x_out_max << 2; |
- assert(!WebPRescalerOutputDone(wrk)); |
- assert(wrk->y_accum <= 0); |
- assert(wrk->y_expand); |
- assert(wrk->y_sub != 0); |
- if (wrk->y_accum == 0) { |
- __asm__ volatile ( |
- "li %[temp3], 0x10000 \n\t" |
- "li %[temp4], 0x8000 \n\t" |
- "addu %[loop_end], %[frow], %[temp6] \n\t" |
- "1: \n\t" |
- "lw %[temp0], 0(%[frow]) \n\t" |
- "addiu %[dst], %[dst], 1 \n\t" |
- "addiu %[frow], %[frow], 4 \n\t" |
- "mult %[temp3], %[temp4] \n\t" |
- "maddu %[temp0], %[temp2] \n\t" |
- "mfhi %[temp5] \n\t" |
- "sb %[temp5], -1(%[dst]) \n\t" |
- "bne %[frow], %[loop_end], 1b \n\t" |
- : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), |
- [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow), |
- [dst]"+r"(dst), [loop_end]"=&r"(loop_end) |
- : [temp2]"r"(temp2), [temp6]"r"(temp6) |
- : "memory", "hi", "lo" |
- ); |
- } else { |
- const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub); |
- const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B); |
- __asm__ volatile ( |
- "li %[temp3], 0x10000 \n\t" |
- "li %[temp4], 0x8000 \n\t" |
- "addu %[loop_end], %[frow], %[temp6] \n\t" |
- "1: \n\t" |
- "lw %[temp0], 0(%[frow]) \n\t" |
- "lw %[temp1], 0(%[irow]) \n\t" |
- "addiu %[dst], %[dst], 1 \n\t" |
- "mult %[temp3], %[temp4] \n\t" |
- "maddu %[A], %[temp0] \n\t" |
- "maddu %[B], %[temp1] \n\t" |
- "addiu %[frow], %[frow], 4 \n\t" |
- "addiu %[irow], %[irow], 4 \n\t" |
- "mfhi %[temp5] \n\t" |
- "mult %[temp3], %[temp4] \n\t" |
- "maddu %[temp5], %[temp2] \n\t" |
- "mfhi %[temp5] \n\t" |
- "sb %[temp5], -1(%[dst]) \n\t" |
- "bne %[frow], %[loop_end], 1b \n\t" |
- : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), |
- [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow), |
- [irow]"+r"(irow), [dst]"+r"(dst), [loop_end]"=&r"(loop_end) |
- : [temp2]"r"(temp2), [temp6]"r"(temp6), [A]"r"(A), [B]"r"(B) |
- : "memory", "hi", "lo" |
- ); |
- } |
-} |
- |
-static void ExportRowShrinkMIPS(WebPRescaler* const wrk) { |
- const int x_out_max = wrk->dst_width * wrk->num_channels; |
- uint8_t* dst = wrk->dst; |
- rescaler_t* irow = wrk->irow; |
- const rescaler_t* frow = wrk->frow; |
- const int yscale = wrk->fy_scale * (-wrk->y_accum); |
- int temp0, temp1, temp3, temp4, temp5, loop_end; |
- const int temp2 = (int)wrk->fxy_scale; |
- const int temp6 = x_out_max << 2; |
- |
- assert(!WebPRescalerOutputDone(wrk)); |
- assert(wrk->y_accum <= 0); |
- assert(!wrk->y_expand); |
- assert(wrk->fxy_scale != 0); |
- if (yscale) { |
- __asm__ volatile ( |
- "li %[temp3], 0x10000 \n\t" |
- "li %[temp4], 0x8000 \n\t" |
- "addu %[loop_end], %[frow], %[temp6] \n\t" |
- "1: \n\t" |
- "lw %[temp0], 0(%[frow]) \n\t" |
- "mult %[temp3], %[temp4] \n\t" |
- "addiu %[frow], %[frow], 4 \n\t" |
- "maddu %[temp0], %[yscale] \n\t" |
- "mfhi %[temp1] \n\t" |
- "lw %[temp0], 0(%[irow]) \n\t" |
- "addiu %[dst], %[dst], 1 \n\t" |
- "addiu %[irow], %[irow], 4 \n\t" |
- "subu %[temp0], %[temp0], %[temp1] \n\t" |
- "mult %[temp3], %[temp4] \n\t" |
- "maddu %[temp0], %[temp2] \n\t" |
- "mfhi %[temp5] \n\t" |
- "sw %[temp1], -4(%[irow]) \n\t" |
- "sb %[temp5], -1(%[dst]) \n\t" |
- "bne %[frow], %[loop_end], 1b \n\t" |
- : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), |
- [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow), |
- [irow]"+r"(irow), [dst]"+r"(dst), [loop_end]"=&r"(loop_end) |
- : [temp2]"r"(temp2), [yscale]"r"(yscale), [temp6]"r"(temp6) |
- : "memory", "hi", "lo" |
- ); |
- } else { |
- __asm__ volatile ( |
- "li %[temp3], 0x10000 \n\t" |
- "li %[temp4], 0x8000 \n\t" |
- "addu %[loop_end], %[irow], %[temp6] \n\t" |
- "1: \n\t" |
- "lw %[temp0], 0(%[irow]) \n\t" |
- "addiu %[dst], %[dst], 1 \n\t" |
- "addiu %[irow], %[irow], 4 \n\t" |
- "mult %[temp3], %[temp4] \n\t" |
- "maddu %[temp0], %[temp2] \n\t" |
- "mfhi %[temp5] \n\t" |
- "sw $zero, -4(%[irow]) \n\t" |
- "sb %[temp5], -1(%[dst]) \n\t" |
- "bne %[irow], %[loop_end], 1b \n\t" |
- : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3), |
- [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [irow]"+r"(irow), |
- [dst]"+r"(dst), [loop_end]"=&r"(loop_end) |
- : [temp2]"r"(temp2), [temp6]"r"(temp6) |
- : "memory", "hi", "lo" |
- ); |
- } |
-} |
- |
-#endif // WEBP_USE_MIPS32 |
+#include "./rescaler.h" |
//------------------------------------------------------------------------------ |
@@ -510,30 +67,37 @@ void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height, |
wrk->frow = work + num_channels * dst_width; |
memset(work, 0, 2 * dst_width * num_channels * sizeof(*work)); |
- if (WebPRescalerImportRowExpand == NULL) { |
- WebPRescalerImportRowExpand = ImportRowExpandC; |
- WebPRescalerImportRowShrink = ImportRowShrinkC; |
- WebPRescalerExportRowExpand = ExportRowExpandC; |
- WebPRescalerExportRowShrink = ExportRowShrinkC; |
- if (VP8GetCPUInfo != NULL) { |
-#if defined(WEBP_USE_MIPS32) |
- if (VP8GetCPUInfo(kMIPS32)) { |
- WebPRescalerImportRowExpand = ImportRowExpandMIPS; |
- WebPRescalerImportRowShrink = ImportRowShrinkMIPS; |
- WebPRescalerExportRowExpand = ExportRowExpandMIPS; |
- WebPRescalerExportRowShrink = ExportRowShrinkMIPS; |
- } |
-#endif |
+ WebPRescalerDspInit(); |
+} |
+ |
+int WebPRescalerGetScaledDimensions(int src_width, int src_height, |
+ int* const scaled_width, |
+ int* const scaled_height) { |
+ assert(scaled_width != NULL); |
+ assert(scaled_height != NULL); |
+ { |
+ int width = *scaled_width; |
+ int height = *scaled_height; |
+ |
+ // if width is unspecified, scale original proportionally to height ratio. |
+ if (width == 0) { |
+ width = (src_width * height + src_height / 2) / src_height; |
} |
+ // if height is unspecified, scale original proportionally to width ratio. |
+ if (height == 0) { |
+ height = (src_height * width + src_width / 2) / src_width; |
+ } |
+ // Check if the overall dimensions still make sense. |
+ if (width <= 0 || height <= 0) { |
+ return 0; |
+ } |
+ |
+ *scaled_width = width; |
+ *scaled_height = height; |
+ return 1; |
} |
} |
-#undef MULT_FIX |
-#undef WEBP_RESCALER_RFIX |
-#undef WEBP_RESCALER_ONE |
-#undef WEBP_RESCALER_FRAC |
-#undef ROUNDER |
- |
//------------------------------------------------------------------------------ |
// all-in-one calls |