/* libs/graphics/sgl/SkAlphaRuns.cpp
**
** Copyright 2006, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include "SkAntiRun.h"
#include "SkUtils.h"
void SkAlphaRuns::reset(int width) {
SkASSERT(width > 0);
#ifdef SK_DEBUG
sk_memset16((uint16_t*)fRuns, (uint16_t)(-42), width);
#endif
fRuns[0] = SkToS16(width);
fRuns[width] = 0;
fAlpha[0] = 0;
SkDEBUGCODE(fWidth = width;)
SkDEBUGCODE(this->validate();)
}
void SkAlphaRuns::Break(int16_t runs[], uint8_t alpha[], int x, int count) {
SkASSERT(count > 0 && x >= 0);
// SkAlphaRuns::BreakAt(runs, alpha, x);
// SkAlphaRuns::BreakAt(&runs[x], &alpha[x], count);
int16_t* next_runs = runs + x;
uint8_t* next_alpha = alpha + x;
while (x > 0) {
int n = runs[0];
SkASSERT(n > 0);
if (x < n) {
alpha[x] = alpha[0];
runs[0] = SkToS16(x);
runs[x] = SkToS16(n - x);
break;
}
runs += n;
alpha += n;
x -= n;
}
runs = next_runs;
alpha = next_alpha;
x = count;
for (;;) {
int n = runs[0];
SkASSERT(n > 0);
if (x < n) {
alpha[x] = alpha[0];
runs[0] = SkToS16(x);
runs[x] = SkToS16(n - x);
break;
}
x -= n;
if (x <= 0) {
break;
}
runs += n;
alpha += n;
}
}
int SkAlphaRuns::add(int x, U8CPU startAlpha, int middleCount, U8CPU stopAlpha,
U8CPU maxValue, int offsetX) {
SkASSERT(middleCount >= 0);
SkASSERT(x >= 0 && x + (startAlpha != 0) + middleCount + (stopAlpha != 0) <= fWidth);
SkASSERT(fRuns[offsetX] >= 0);
int16_t* runs = fRuns + offsetX;
uint8_t* alpha = fAlpha + offsetX;
uint8_t* lastAlpha = alpha;
x -= offsetX;
if (startAlpha) {
SkAlphaRuns::Break(runs, alpha, x, 1);
/* I should be able to just add alpha[x] + startAlpha.
However, if the trailing edge of the previous span and the leading
edge of the current span round to the same super-sampled x value,
I might overflow to 256 with this add, hence the funny subtract (crud).
*/
unsigned tmp = alpha[x] + startAlpha;
SkASSERT(tmp <= 256);
alpha[x] = SkToU8(tmp - (tmp >> 8)); // was (tmp >> 7), but that seems wrong if we're trying to catch 256
runs += x + 1;
alpha += x + 1;
x = 0;
lastAlpha += x; // we don't want the +1
SkDEBUGCODE(this->validate();)
}
if (middleCount) {
SkAlphaRuns::Break(runs, alpha, x, middleCount);
alpha += x;
runs += x;
x = 0;
do {
alpha[0] = SkToU8(alpha[0] + maxValue);
int n = runs[0];
SkASSERT(n <= middleCount);
alpha += n;
runs += n;
middleCount -= n;
} while (middleCount > 0);
SkDEBUGCODE(this->validate();)
lastAlpha = alpha;
}
if (stopAlpha) {
SkAlphaRuns::Break(runs, alpha, x, 1);
alpha += x;
alpha[0] = SkToU8(alpha[0] + stopAlpha);
SkDEBUGCODE(this->validate();)
lastAlpha = alpha;
}
return lastAlpha - fAlpha; // new offsetX
}
#ifdef SK_DEBUG
void SkAlphaRuns::assertValid(int y, int maxStep) const {
int max = (y + 1) * maxStep - (y == maxStep - 1);
const int16_t* runs = fRuns;
const uint8_t* alpha = fAlpha;
while (*runs) {
SkASSERT(*alpha <= max);
alpha += *runs;
runs += *runs;
}
}
void SkAlphaRuns::dump() const {
const int16_t* runs = fRuns;
const uint8_t* alpha = fAlpha;
SkDebugf("Runs");
while (*runs) {
int n = *runs;
SkDebugf(" %02x", *alpha);
if (n > 1) {
SkDebugf(",%d", n);
}
alpha += n;
runs += n;
}
SkDebugf("\n");
}
void SkAlphaRuns::validate() const {
SkASSERT(fWidth > 0);
int count = 0;
const int16_t* runs = fRuns;
while (*runs) {
SkASSERT(*runs > 0);
count += *runs;
SkASSERT(count <= fWidth);
runs += *runs;
}
SkASSERT(count == fWidth);
}
#endif