Skip to content

Commit 7d65dc4

Browse files
Enrico Roshyperb1iss
authored andcommitted
webkit: Color Inversion for power saving and eye strain relief
This patch allows to set an 'inversion flag' on the Web View to render the content (but not images) inverting the color. The typical usage is when rendering some black text on white page: using color inversion you get a more readable text and you save power at the same time. This patch is based on ec1ce8d8eac4a768b5888fe956a3defc7d457f6f. Change-Id: I0693426589bd5f8c83457a5b8899fe5b85285120
1 parent 087e8ba commit 7d65dc4

File tree

4 files changed

+87
-9
lines changed

4 files changed

+87
-9
lines changed

WebKit/android/jni/PictureSet.cpp

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@
3737
#include "SkRect.h"
3838
#include "SkRegion.h"
3939
#include "SkStream.h"
40+
#include "SyncProxyCanvas.h"
4041
#include "TimeCounter.h"
4142

4243
#ifdef CACHED_IMAGE_DECODE
4344
#include <wtf/PassOwnPtr.h>
4445
#include "SkPixelRef.h"
45-
#include "SyncProxyCanvas.h"
4646
#endif
4747

4848
#define MAX_DRAW_TIME 100
@@ -247,8 +247,9 @@ class BitmapProxyCanvas: public SyncProxyCanvas, public Noncopyable
247247
public:
248248
static WTF::PassOwnPtr<BitmapProxyCanvas> create(SkCanvas* canvas,
249249
WTF::Vector<const SkBitmap*>* pBitmaps,
250-
WTF::Vector<SkRect>* pBitmapRects) {
251-
return new BitmapProxyCanvas(canvas, pBitmaps, pBitmapRects);
250+
WTF::Vector<SkRect>* pBitmapRects,
251+
bool invert) {
252+
return new BitmapProxyCanvas(canvas, pBitmaps, pBitmapRects, invert);
252253
}
253254

254255
virtual void drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
@@ -265,6 +266,16 @@ class BitmapProxyCanvas: public SyncProxyCanvas, public Noncopyable
265266
appendBitmap(bitmap, fastBounds);
266267
} else {
267268
target->drawBitmap(bitmap, x, y, paint);
269+
if (invertBitmaps) {
270+
target->save();
271+
SkRect inversionRect;
272+
inversionRect.set(x, y,
273+
x + SkIntToScalar(bitmap.width()),
274+
y + SkIntToScalar(bitmap.height()));
275+
target->clipRect(inversionRect);
276+
target->drawARGB(255, 255, 255, 255, SkXfermode::kDifference_Mode);
277+
target->restore();
278+
}
268279
}
269280
}
270281

@@ -278,6 +289,12 @@ class BitmapProxyCanvas: public SyncProxyCanvas, public Noncopyable
278289
appendBitmap(bitmap, dst);
279290
} else {
280291
target->drawBitmapRect(bitmap, src, dst, paint);
292+
if (invertBitmaps) {
293+
target->save();
294+
target->clipRect(dst);
295+
target->drawARGB(255, 255, 255, 255, SkXfermode::kDifference_Mode);
296+
target->restore();
297+
}
281298
}
282299
}
283300

@@ -290,13 +307,16 @@ class BitmapProxyCanvas: public SyncProxyCanvas, public Noncopyable
290307

291308
WTF::Vector<const SkBitmap*> *pBitmapsForDecoding;
292309
WTF::Vector<SkRect> *pBitmapRectsForDecoding;
310+
bool invertBitmaps;
293311

294312
BitmapProxyCanvas(SkCanvas* canvas,
295313
WTF::Vector<const SkBitmap*> *pBitmaps,
296-
WTF::Vector<SkRect> *pBitmapRects)
314+
WTF::Vector<SkRect> *pBitmapRects,
315+
bool invert)
297316
: SyncProxyCanvas(canvas)
298317
, pBitmapsForDecoding(pBitmaps)
299318
, pBitmapRectsForDecoding(pBitmapRects)
319+
, invertBitmaps(invert)
300320
{
301321
}
302322

@@ -342,9 +362,38 @@ class BitmapProxyCanvas: public SyncProxyCanvas, public Noncopyable
342362
}
343363
};
344364

365+
#else
366+
class ImageInverter: public SyncProxyCanvas
367+
{
368+
public:
369+
370+
ImageInverter(SkCanvas* canvas): SyncProxyCanvas(canvas) {}
371+
372+
void drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
373+
const SkPaint* paint) {
374+
target->drawBitmap(bitmap, x, y, paint);
375+
target->save();
376+
SkRect inversionRect;
377+
inversionRect.set(x, y,
378+
x + SkIntToScalar(bitmap.width()),
379+
y + SkIntToScalar(bitmap.height()));
380+
target->clipRect(inversionRect);
381+
target->drawARGB(255, 255, 255, 255, SkXfermode::kDifference_Mode);
382+
target->restore();
383+
}
384+
385+
void drawBitmapRect(const SkBitmap& bitmap, const SkIRect* src,
386+
const SkRect& dst, const SkPaint* paint) {
387+
target->drawBitmapRect(bitmap, src, dst, paint);
388+
target->save();
389+
target->clipRect(dst);
390+
target->drawARGB(255, 255, 255, 255, SkXfermode::kDifference_Mode);
391+
target->restore();
392+
}
393+
};
345394
#endif
346395

347-
bool PictureSet::draw(SkCanvas* canvas)
396+
bool PictureSet::draw(SkCanvas* canvas, bool invertColor)
348397
{
349398
validate(__FUNCTION__);
350399
Pictures* first = mPictures.begin();
@@ -405,11 +454,14 @@ bool PictureSet::draw(SkCanvas* canvas)
405454
uint32_t startTime = getThreadMsec();
406455
#ifdef CACHED_IMAGE_DECODE
407456
{
408-
WTF::OwnPtr<BitmapProxyCanvas> proxyCanvas = BitmapProxyCanvas::create(canvas, &mBitmapsForDecoding, &mBitmapRectsForDecoding);
457+
WTF::OwnPtr<BitmapProxyCanvas> proxyCanvas = BitmapProxyCanvas::create(canvas, &mBitmapsForDecoding, &mBitmapRectsForDecoding, invertColor);
409458
proxyCanvas->drawPicture(*working->mPicture);
410459
}
411460
#else
412-
canvas->drawPicture(*working->mPicture);
461+
SkCanvas* painter = invertColor ? new ImageInverter(canvas) : canvas;
462+
painter->drawPicture(*working->mPicture);
463+
if (invertColor)
464+
delete painter;
413465
#endif
414466
size_t elapsed = working->mElapsed = getThreadMsec() - startTime;
415467
working->mWroteElapsed = true;
@@ -441,6 +493,8 @@ bool PictureSet::draw(SkCanvas* canvas)
441493
working->mElapsed, working->mBase ? "true" : "false");
442494
}
443495
// dump(__FUNCTION__);
496+
if (invertColor)
497+
canvas->drawARGB(255, 255, 255, 255, SkXfermode::kDifference_Mode);
444498
return maxElapsed >= MAX_DRAW_TIME;
445499
}
446500

WebKit/android/jni/PictureSet.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ namespace android {
7070
// Update mWidth/mHeight, and adds any additional inval region
7171
void checkDimensions(int width, int height, SkRegion* inval);
7272
void clear();
73-
bool draw(SkCanvas* );
73+
bool draw(SkCanvas* , bool invertColor = false);
7474
static PictureSet* GetNativePictureSet(JNIEnv* env, jobject jpic);
7575
int height() const { return mHeight; }
7676
bool isEmpty() const; // returns true if empty or only trivial content

WebKit/android/jni/WebViewCore.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ WebViewCore::WebViewCore(JNIEnv* env, jobject javaWebViewCore, WebCore::Frame* m
302302
m_forwardingTouchEvents = false;
303303
#endif
304304
m_isPaused = false;
305+
m_invertColor = false;
305306

306307
LOG_ASSERT(m_mainFrame, "Uh oh, somehow a frameview was made without an initial frame!");
307308

@@ -791,7 +792,7 @@ bool WebViewCore::drawContent(SkCanvas* canvas, SkColor color)
791792
canvas->clipRect(clip, SkRegion::kDifference_Op);
792793
canvas->drawColor(color);
793794
canvas->restoreToCount(sc);
794-
bool tookTooLong = copyContent.draw(canvas);
795+
bool tookTooLong = copyContent.draw(canvas, m_invertColor);
795796
m_contentMutex.lock();
796797
m_content.setDrawTimes(copyContent);
797798
m_contentMutex.unlock();
@@ -2448,6 +2449,17 @@ void WebViewCore::setBackgroundColor(SkColor c)
24482449
view->setTransparent(true);
24492450
}
24502451

2452+
void WebViewCore::setColorInversion(bool invert)
2453+
{
2454+
if (m_invertColor != invert) {
2455+
m_invertColor = invert;
2456+
if (invert)
2457+
DBG_SET_LOG("color invert active");
2458+
else
2459+
DBG_SET_LOG("no color invert");
2460+
}
2461+
}
2462+
24512463
jclass WebViewCore::getPluginClass(const WebCore::String& libName, const char* className)
24522464
{
24532465
JNIEnv* env = JSC::Bindings::getJNIEnv();
@@ -2969,6 +2981,14 @@ static void SetBackgroundColor(JNIEnv *env, jobject obj, jint color)
29692981
viewImpl->setBackgroundColor((SkColor) color);
29702982
}
29712983

2984+
static void SetColorInversion(JNIEnv *env, jobject obj, jboolean invert)
2985+
{
2986+
WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
2987+
LOG_ASSERT(viewImpl, "viewImpl not set in %s", __FUNCTION__);
2988+
2989+
viewImpl->setColorInversion(invert);
2990+
}
2991+
29722992
static void DumpDomTree(JNIEnv *env, jobject obj, jboolean useFile)
29732993
{
29742994
WebViewCore* viewImpl = GET_NATIVE_VIEW(env, obj);
@@ -3248,6 +3268,8 @@ static JNINativeMethod gJavaWebViewCoreMethods[] = {
32483268
(void*) SplitContent },
32493269
{ "nativeSetBackgroundColor", "(I)V",
32503270
(void*) SetBackgroundColor },
3271+
{ "nativeSetColorInversion", "(Z)V",
3272+
(void*) SetColorInversion },
32513273
{ "nativeRegisterURLSchemeAsLocal", "(Ljava/lang/String;)V",
32523274
(void*) RegisterURLSchemeAsLocal },
32533275
{ "nativeDumpDomTree", "(Z)V",

WebKit/android/jni/WebViewCore.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,7 @@ namespace android {
362362
jobject getWebViewJavaObject();
363363

364364
void setBackgroundColor(SkColor c);
365+
void setColorInversion(bool invert);
365366
void updateFrameCache();
366367
void updateCacheOnNodeChange();
367368
void dumpDomTree(bool);
@@ -546,6 +547,7 @@ namespace android {
546547
bool m_check_domtree_version;
547548
PageGroup* m_groupForVisitedLinks;
548549
bool m_isPaused;
550+
bool m_invertColor;
549551

550552
SkTDArray<PluginWidgetAndroid*> m_plugins;
551553
WebCore::Timer<WebViewCore> m_pluginInvalTimer;

0 commit comments

Comments
 (0)