blob: 3964ee1a51b13bf6c6f908a029f2c38213b709cd [file] [log] [blame]
/*
*
* Copyright 2007, 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 "config.h"
#include "android_graphics.h"
#include "IntPoint.h"
#include "IntRect.h"
#include "FloatPoint.h"
#include "FloatRect.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
#include "SkCornerPathEffect.h"
#include "SkGradientShader.h"
#include "SkPath.h"
#include "SkRegion.h"
SkPoint* android_setpt(SkPoint* dst, const WebCore::IntPoint& src)
{
dst->set(SkIntToScalar(src.x()), SkIntToScalar(src.y()));
return dst;
}
SkPoint* android_setpt(SkPoint* dst, const WebCore::FloatPoint& src)
{
dst->set(SkFloatToScalar(src.x()), SkFloatToScalar(src.y()));
return dst;
}
SkRect* android_setrect(SkRect* dst, const WebCore::IntRect& src)
{
dst->set(SkIntToScalar(src.x()),
SkIntToScalar(src.y()),
SkIntToScalar(src.x() + src.width()),
SkIntToScalar(src.y() + src.height()));
return dst;
}
SkIRect* android_setrect(SkIRect* dst, const WebCore::IntRect& src)
{
dst->set(src.x(), src.y(),
src.x() + src.width(),
src.y() + src.height());
return dst;
}
SkRect* android_setrect(SkRect* dst, const WebCore::FloatRect& src)
{
dst->set(SkFloatToScalar(src.x()),
SkFloatToScalar(src.y()),
SkFloatToScalar(src.x() + src.width()),
SkFloatToScalar(src.y() + src.height()));
return dst;
}
SkIRect* android_setrect(SkIRect* dst, const WebCore::FloatRect& src)
{
dst->set(SkScalarRound(SkFloatToScalar(src.x())),
SkScalarRound(SkFloatToScalar(src.y())),
SkScalarRound(SkFloatToScalar(src.x() + src.width())),
SkScalarRound(SkFloatToScalar(src.y() + src.height())));
return dst;
}
SkIRect* android_setrect_scaled(SkIRect* dst, const WebCore::FloatRect& src,
float sx, float sy)
{
dst->set(SkScalarRound(SkFloatToScalar(src.x() * sx)),
SkScalarRound(SkFloatToScalar(src.y() * sy)),
SkScalarRound(SkFloatToScalar((src.x() + src.width()) * sx)),
SkScalarRound(SkFloatToScalar((src.y() + src.height()) * sy)));
return dst;
}
static const struct CompositOpToPorterDuffMode {
uint8_t mCompositOp;
uint8_t mPorterDuffMode;
} gMapCompositOpsToPorterDuffModes[] = {
{ WebCore::CompositeClear, SkPorterDuff::kClear_Mode },
{ WebCore::CompositeCopy, SkPorterDuff::kSrcOver_Mode }, // TODO
{ WebCore::CompositeSourceOver, SkPorterDuff::kSrcOver_Mode },
{ WebCore::CompositeSourceIn, SkPorterDuff::kSrcIn_Mode },
{ WebCore::CompositeSourceOut, SkPorterDuff::kSrcOut_Mode },
{ WebCore::CompositeSourceAtop, SkPorterDuff::kSrcATop_Mode },
{ WebCore::CompositeDestinationOver, SkPorterDuff::kDstOver_Mode },
{ WebCore::CompositeDestinationIn, SkPorterDuff::kDstIn_Mode },
{ WebCore::CompositeDestinationOut, SkPorterDuff::kDstOut_Mode },
{ WebCore::CompositeDestinationAtop, SkPorterDuff::kDstATop_Mode },
{ WebCore::CompositeXOR, SkPorterDuff::kXor_Mode },
{ WebCore::CompositePlusDarker, SkPorterDuff::kDarken_Mode },
{ WebCore::CompositeHighlight, SkPorterDuff::kSrcOver_Mode }, // TODO
{ WebCore::CompositePlusLighter, SkPorterDuff::kLighten_Mode }
};
SkPorterDuff::Mode android_convert_compositeOp(WebCore::CompositeOperator op)
{
const CompositOpToPorterDuffMode* table = gMapCompositOpsToPorterDuffModes;
for (unsigned i = 0; i < SK_ARRAY_COUNT(gMapCompositOpsToPorterDuffModes); i++) {
if (table[i].mCompositOp == op) {
return (SkPorterDuff::Mode)table[i].mPorterDuffMode;
}
}
SkDEBUGF(("GraphicsContext::setCompositeOperation uknown CompositOperator %d\n", op));
return SkPorterDuff::kSrcOver_Mode; // fall-back
}
SkShader::TileMode android_convert_TileRule(WebCore::Image::TileRule rule)
{
// stretch == clamp
// repeat == repeat
// RoundTile???
return WebCore::Image::RepeatTile == rule ? SkShader::kRepeat_TileMode : SkShader::kClamp_TileMode;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////
static U8CPU InvScaleByte(U8CPU component, uint32_t scale)
{
SkASSERT(component == (uint8_t)component);
return (component * scale + 0x8000) >> 16;
}
// move this guy into SkColor.h
static SkColor SkPMColorToColor(SkPMColor pm)
{
if (0 == pm)
return 0;
unsigned a = SkGetPackedA32(pm);
uint32_t scale = (255 << 16) / a;
return SkColorSetARGB(a,
InvScaleByte(SkGetPackedR32(pm), scale),
InvScaleByte(SkGetPackedG32(pm), scale),
InvScaleByte(SkGetPackedB32(pm), scale));
}
WebCore::Color android_SkPMColorToWebCoreColor(SkPMColor pm)
{
SkColor c = SkPMColorToColor(pm);
return WebCore::Color(SkColorGetR(c), SkColorGetG(c), SkColorGetB(c), SkColorGetA(c));
}
const static SkColor focusOuterColors[] = {
SkColorSetARGB(0xff, 0xB3, 0x3F, 0x08), // normal focus ring select
SkColorSetARGB(0xff, 0x46, 0xb0, 0x00), // fake focus ring select, for phone, email, text
SkColorSetARGB(0x00, 0x00, 0x00, 0x00), // no ring, for buttons
SkColorSetARGB(0xff, 0xb0, 0x16, 0x00), // invalid focus ring color
SkColorSetARGB(0xff, 0xAD, 0x5C, 0x0A), // normal focus ring pressed
SkColorSetARGB(0xff, 0x36, 0xc0, 0x00) // fake focus ring pressed
};
const static SkColor focusInnerColors[] = {
SkColorSetARGB(0xff, 0xFE, 0x92, 0x30), // normal focus ring select
SkColorSetARGB(0xff, 0x8c, 0xd9, 0x00), // fake focus ring select, for phone, email, text
SkColorSetARGB(0x00, 0x00, 0x00, 0x00), // no ring, for buttons
SkColorSetARGB(0xff, 0xd9, 0x2c, 0x00), // invalid focus ring color
SkColorSetARGB(0xff, 0xFE, 0xBD, 0x3A), // normal focus ring pressed
SkColorSetARGB(0xff, 0x7c, 0xe9, 0x00) // fake focus ring pressed
};
const static SkColor focusPressedColors[] = {
SkColorSetARGB(0x80, 0xFF, 0xC6, 0x4B), // normal focus ring pressed
SkColorSetARGB(0x80, 0x7c, 0xe9, 0x00), // fake focus ring pressed
SkColorSetARGB(0x80, 0xFF, 0xC6, 0x4B) // button focus ring pressed
};
#define FOCUS_RING_ROUNDEDNESS SkIntToScalar(5) // used to draw corners
#define FOCUS_RING_INNER_DIAMETER SkFixedToScalar(SkIntToFixed(3)>>1) // 3/2 == 1.5
#define FOCUS_RING_OUTER_OUTSET 2 // used to inflate rects added to region
void FocusRing::DrawRing(SkCanvas* canvas,
const Vector<WebCore::IntRect>& rects, Flavor flavor)
{
unsigned rectCount = rects.size();
SkRegion rgn;
SkPath path;
for (unsigned i = 0; i < rectCount; i++)
{
SkIRect r;
android_setrect(&r, rects[i]);
r.inset(-FOCUS_RING_OUTER_OUTSET, -FOCUS_RING_OUTER_OUTSET);
rgn.op(r, SkRegion::kUnion_Op);
}
rgn.getBoundaryPath(&path);
SkPaint paint;
paint.setAntiAlias(true);
paint.setPathEffect(new SkCornerPathEffect(FOCUS_RING_ROUNDEDNESS))->unref();
if (flavor >= NORMAL_ANIMATING) { // pressed
paint.setColor(focusPressedColors[flavor - NORMAL_ANIMATING]);
canvas->drawPath(path, paint);
}
if (flavor == BUTTON_ANIMATING)
return;
paint.setStyle(SkPaint::kStroke_Style);
paint.setStrokeWidth(FOCUS_RING_OUTER_DIAMETER);
paint.setColor(focusOuterColors[flavor]);
canvas->drawPath(path, paint);
paint.setStrokeWidth(FOCUS_RING_INNER_DIAMETER);
paint.setColor(focusInnerColors[flavor]);
canvas->drawPath(path, paint);
}