1.fix textview's layout isssues;2.add jpegdecoder

This commit is contained in:
houzh 2023-12-14 10:00:39 +08:00
parent 44d1043ecb
commit b3db09a793
15 changed files with 245 additions and 38 deletions

View File

@ -7,7 +7,7 @@ int main(int argc,const char*argv[]){
cdroid::Context*ctx=&app;
Window*w=new Window(0,0,-1,-1);
w->setId(1);
Drawable*d=nullptr;
Drawable*d=nullptr;
StateListDrawable*sd;
CompoundButton*chk;
LOGD("test LOGF %d",__LINE__);
@ -16,6 +16,15 @@ int main(int argc,const char*argv[]){
Button *btn=new Button("Button",120,60);
d=ctx->getDrawable("cdroid:drawable/btn_default.xml");
sd=dynamic_cast<StateListDrawable*>(d);
w->setBackgroundColor(0xFF101112);
btn->setOnTouchListener([](View&v,MotionEvent&e){
const bool down=e.getAction()==MotionEvent::ACTION_DOWN;
v.setTranslationX(down?0.1f*v.getWidth():0);
v.setTranslationY(down?0.1f*v.getHeight():0);
v.setScaleX(down?0.8f:1.f);
v.setScaleY(down?0.8f:1.f);
return false;
});
LOGD("%p statecount=%d",sd,sd->getStateCount());
btn->setBackground(d);
btn->setBackgroundTintList(ctx->getColorStateList("cdroid:color/textview"));

View File

@ -1,7 +1,7 @@
/* This file is part of cairomm. */
/* Defined when the --enable-api-exceptions configure argument was given */
//#define CAIROMM_EXCEPTIONS_ENABLED 1
#define CAIROMM_EXCEPTIONS_ENABLED 1
/* Major version number of cairomm. */
#define CAIROMM_MAJOR_VERSION 1
@ -25,4 +25,4 @@
#if defined(_MSC_VER) && (_MSC_VER < 1900)
#define _ALLOW_KEYWORD_MACROS 1
#define noexcept _NOEXCEPT
#endif
#endif

View File

@ -549,9 +549,9 @@ void Assets::clearStyles() {
mStyles.clear();
}
AttributeSet Assets::obtainStyledAttributes(const std::string&refname) {
AttributeSet Assets::obtainStyledAttributes(const std::string&resname) {
AttributeSet atts;
std::string pkg,name = refname;
std::string pkg,name = resname;
size_t pos = name.find("attr");
while(pos!=std::string::npos) {
name = name.replace(pos,4,"style");

View File

@ -228,7 +228,7 @@ void GraphDevice::composeSurfaces(){
mPrimaryContext->set_operator(Cairo::Context::Operator::SOURCE);
for(int i=0;i< wSurfaces.size();i++){
Rect rcw = wBounds[i];
RefPtr<Region> rgn = wins[i]->mPendingRgn;//winVisibleRgns[i];//wins[i]->mVisibleRgn;
RefPtr<Region> rgn = wins[i]->mPendingRgn;
HANDLE hdlSurface = wSurfaces[i]->mHandle;
if(rgn->empty())continue;
rgn->intersect(wins[i]->mVisibleRgn);/*it is already empty*/
@ -262,7 +262,7 @@ void GraphDevice::composeSurfaces(){
mPrimaryContext->set_source(wSurfaces[i]->get_target(),rcw.left,rcw.top);
mPrimaryContext->fill();
}
rgn->subtract(rgn);//wins[i]->mPendingRgn->subtract(wins[i]->mPendingRgn);
rgn->subtract(rgn);
}/*endif for wSurfaces.size*/
GFXFlip(mPrimarySurface);
mLastComposeTime = SystemClock::uptimeMillis();

View File

@ -5,7 +5,7 @@
#include <image-decoders/imagedecoder.h>
#include <porting/cdgraph.h>
namespace cdroid{
#define ENEBLE_DMABLIT 0
#define ENABLE_DMABLIT 1
AnimatedImageDrawable::AnimatedImageDrawable()
:AnimatedImageDrawable(std::make_shared<AnimatedImageState>()){
}
@ -126,7 +126,7 @@ void AnimatedImageDrawable::draw(Canvas& canvas){
}else{
#if ENABLE(DMABLIT)
Rect rd={0,0,mBounds.width,mBounds.height};
GFXBlit(handler,(const GFXRect*)&rd,mImageHandler,nullptr,0);
GFXBlit(handler,0,0,mImageHandler,nullptr);
#endif
}
canvas.restore();

View File

@ -141,8 +141,8 @@ void ColorDrawable::draw(Canvas&canvas){
canvas.set_color(mColorState->mUseColor);
if(mTintFilter)
canvas.set_operator((Cairo::Context::Operator)ColorFilter::tintMode2CairoOperator(mTintFilter->getMode()));
else if((mTintFilter==nullptr)&&(mColorState->mTintMode!=NOOP))
;//canvas.set_operator((Cairo::Context::Operator)ColorFilter::tintMode2CairoOperator(mColorState->mTintMode));
else if(mTintFilter&&(mColorState->mTintMode!=NOOP))
canvas.set_operator((Cairo::Context::Operator)ColorFilter::tintMode2CairoOperator(mColorState->mTintMode));
/*HANDLE handler = canvas.getHandler();
if(handler&&(mBounds.width==1024||mBounds.width==600)){
GFXFillRect(handler,nullptr,mColorState->mUseColor);

View File

@ -13,7 +13,8 @@ namespace cdroid{
ImageDecoder::ImageDecoder(){
mImageWidth = -1;
mImageHeight= -1;
mFrameCount =0;
mFrameCount = 0;
mScale = 1.f;
mPrivate = nullptr;
}
@ -32,6 +33,14 @@ int ImageDecoder::getFrameCount()const{
return mFrameCount;
}
float ImageDecoder::getScale()const{
return mScale;
}
void ImageDecoder::setScale(float s){
mScale =s;
}
int ImageDecoder::getFrameDuration(int idx)const{
int duration = 0;//( (idx>=0) && (idx<mFrameCount) ) ? mFrames[idx]->duration:INT_MAX;
// Many annoying ads specify a 0 duration to make an image flash as quickly as possible.
@ -103,9 +112,9 @@ ImageDecoder*ImageDecoder::create(Context*ctx,const std::string&resourceId){
if (matchesICOSignature(contents) || matchesCURSignature(contents))
return ICOImageDecoder::create(alphaOption, gammaAndColorProfileOption);
#endif
#if USE(JPEG)
#if ENABLE(JPEG)
if (matchesJPEGSignature(contents))
return JPEGImageDecoder::create(alphaOption, gammaAndColorProfileOption);
decoder = new JPEGDecoder();//::create(alphaOption, gammaAndColorProfileOption);
#endif
#if USE(OPENJPEG)
if (matchesJP2Signature(contents))

View File

@ -14,12 +14,15 @@ protected:
int mFrameCount;
int mImageWidth;
int mImageHeight;
float mScale;
public:
ImageDecoder();
virtual ~ImageDecoder();
virtual int load(std::istream&)=0;
int getWidth()const;
int getHeight()const;
float getScale()const;
void setScale(float);
virtual int getFrameCount()const;
virtual int getFrameDuration(int)const;
virtual int readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int frameIndex)=0;
@ -36,6 +39,13 @@ public:
int readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int frameIndex)override;
};
class JPEGDecoder:public ImageDecoder{
public:
JPEGDecoder();
int load(std::istream&)override;
int readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int frameIndex)override;
};
class APNGDecoder:public ImageDecoder{
public:
APNGDecoder();

View File

@ -0,0 +1,162 @@
#include <stdio.h>
#include <stddef.h>
#include <setjmp.h>
#include <jpeglib.h>
#include <turbojpeg.h>
#include <image-decoders/imagedecoder.h>
#include <cdlog.h>
namespace cdroid{
JPEGDecoder::JPEGDecoder(){
}
struct decoder_error_mgr {
struct jpeg_error_mgr pub; // "public" fields for IJG library
jmp_buf setjmp_buffer; // For handling catastropic errors
};
struct JpegStream {
jpeg_source_mgr pub;
std::istream* stream;
unsigned char buffer [4096];
};
static void init_source (j_decompress_ptr cinfo) {
auto src = (JpegStream*)(cinfo->src);
}
static void handle_jpeg_error(j_common_ptr cinfo) {
struct decoder_error_mgr *err = (struct decoder_error_mgr*)(cinfo->err);
jpeg_destroy_decompress((j_decompress_ptr)cinfo);
longjmp(err->setjmp_buffer, 1);
LOGE("JPEG read/write error");
}
static boolean fill_buffer (j_decompress_ptr cinfo) {
// Read to buffer
JpegStream* src = (JpegStream*)(cinfo->src);
src->stream->read((char*)src->buffer,sizeof(src->buffer));
src->pub.next_input_byte = src->buffer;
src->pub.bytes_in_buffer = src->stream->gcount();// How many yo could read
return (!src->stream->eof())||src->pub.bytes_in_buffer;
}
static void skip (j_decompress_ptr cinfo, long num_bytes) {
JpegStream*src = (JpegStream*)cinfo->src;
if (num_bytes > 0) {
while (num_bytes > (long)src->pub.bytes_in_buffer) {
num_bytes -= (long)src->pub.bytes_in_buffer;
(void)(*src->pub.fill_input_buffer) (cinfo);
}
src->pub.next_input_byte += (size_t)num_bytes;
src->pub.bytes_in_buffer -= (size_t)num_bytes;
}
}
static void term (j_decompress_ptr cinfo) {
// Close the stream, can be nop
}
static void make_jpeg_stream (j_decompress_ptr cinfo, std::istream* in) {
JpegStream * src;
if (cinfo->src == NULL) {/* first time for this JPEG object? */
cinfo->src =(struct jpeg_source_mgr*)(*cinfo->mem->alloc_small)((j_common_ptr)cinfo,0/*POOL_PERMANENT*/,sizeof(JpegStream));
src = reinterpret_cast<JpegStream*> (cinfo->src);
}
src = reinterpret_cast<JpegStream*> (cinfo->src);
src->pub.init_source = init_source;
src->pub.fill_input_buffer = fill_buffer;
src->pub.skip_input_data = skip;
src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */
src->pub.term_source = term;
src->stream = in;
src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */
src->pub.next_input_byte = NULL; /* until buffer loaded */
}
static int gcd(int a, int b) {
if (b == 0) return a;
return gcd(b, a % b);
}
// 定义一个函数,将小数转换为最简分数形式
static void decimalToFraction(double decimal,int& scale_num,int& scale_denom) {
const int precision = 1000000; // 精度,可以根据需要调整
const int numerator = decimal * precision;
const int denominator = precision;
const int commonDivisor = gcd(numerator, denominator);
scale_num = numerator / commonDivisor;
scale_denom = denominator / commonDivisor;
}
int JPEGDecoder::readImage(Cairo::RefPtr<Cairo::ImageSurface>image,int frameIndex){
struct jpeg_decompress_struct cinfo;
struct decoder_error_mgr jerr;
int scale_num,scale_denom;
JSAMPROW row_pointer[1];
cairo_surface_t *sfc;
// initialize jpeg decompression structures
if (setjmp(jerr.setjmp_buffer)){
return 0;//sfc;
}
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = handle_jpeg_error;
jpeg_create_decompress(&cinfo);
make_jpeg_stream(&cinfo,nullptr);//&is);
jpeg_read_header(&cinfo, TRUE);
decimalToFraction(mScale,scale_num,scale_denom);
if(scale_num){
cinfo.scale_num = scale_num;
cinfo.scale_denom= scale_denom;
}
#ifdef LIBJPEG_TURBO_VERSION
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
cinfo.out_color_space = JCS_EXT_BGRA;
#else
cinfo.out_color_space = JCS_EXT_ARGB;
#endif
#else
cinfo.out_color_space = JCS_RGB;
#endif
// start decompressor
(void) jpeg_start_decompress(&cinfo);
// create Cairo image surface
sfc = cairo_image_surface_create(CAIRO_FORMAT_RGB24, cinfo.output_width, cinfo.output_height);
if (cairo_surface_status(sfc) != CAIRO_STATUS_SUCCESS) {
jpeg_destroy_decompress(&cinfo);
return 0;//sfc;
}
// loop over all scanlines and fill Cairo image surface
while (cinfo.output_scanline < cinfo.output_height) {
unsigned char *row_address = cairo_image_surface_get_data(sfc) +
(cinfo.output_scanline * cairo_image_surface_get_stride(sfc));
row_pointer[0] = row_address;
if(jpeg_read_scanlines(&cinfo, row_pointer, 1)!=1){
LOGD("jpeg data corrupt at scanline=%d/%d",cinfo.output_scanline,cinfo.output_height);
break;
}
#ifndef LIBJPEG_TURBO_VERSION
pix_conv(row_address, 4, row_address, 3, cinfo.output_width);
#endif
}
// finish and close everything
cairo_surface_mark_dirty(sfc);
(void) jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
// set jpeg mime data
cairo_surface_set_mime_data(sfc, CAIRO_MIME_TYPE_JPEG, NULL, 0, NULL,NULL);
return 0;//sfc;
}
int JPEGDecoder::load(std::istream&){
return 0;
}
}/*endof namespacee*/

View File

@ -206,7 +206,7 @@ View* LayoutInflater::inflate(const std::string&package,std::istream&stream,View
root->requestLayout();
root->startLayoutAnimation();
}
LOGV("usedtime %dms parsed %d views",SystemClock::uptimeMillis() - tstart, pd.parsedView);
LOGV("usedtime %ldms [%p]parsed %d views ",long(SystemClock::uptimeMillis() - tstart),&pd, pd.parsedView);
return pd.returnedView;
}

View File

@ -1105,19 +1105,18 @@ bool View::getDefaultFocusHighlightEnabled()const{
}
bool View::isDefaultFocusHighlightNeeded(const Drawable* background,const Drawable* foreground)const{
bool lackFocusState = (background == nullptr || !background->isStateful()
|| !background->hasFocusStateSpecified())
&& (foreground == nullptr || !foreground->isStateful()
|| !foreground->hasFocusStateSpecified());
const bool lackFocusState =
((background == nullptr) || (false==background->isStateful())|| !background->hasFocusStateSpecified())
&& ((foreground == nullptr) || (false==foreground->isStateful()) || (false==foreground->hasFocusStateSpecified()));
return !isInTouchMode() && getDefaultFocusHighlightEnabled()
&& lackFocusState && isAttachedToWindow();// && sUseDefaultFocusHighlight;
}
void View::switchDefaultFocusHighlight() {
if (isFocused()) {
bool needed = isDefaultFocusHighlightNeeded(mBackground,
mForegroundInfo == nullptr ? nullptr : mForegroundInfo->mDrawable);
bool active = mDefaultFocusHighlight != nullptr;
const bool needed = isDefaultFocusHighlightNeeded(mBackground,
mForegroundInfo ? mForegroundInfo->mDrawable:nullptr);
const bool active = mDefaultFocusHighlight != nullptr;
if (needed && !active) {
setDefaultFocusHighlight(getDefaultFocusHighlightDrawable());
} else if (!needed && active) {
@ -1452,6 +1451,10 @@ int View::combineVisibility(int vis1, int vis2) {
return std::max(vis1, vis2);
}
const Display* View::getDisplay() const{
return mAttachInfo ? mAttachInfo->mDisplay : nullptr;
}
void View::dispatchAttachedToWindow(AttachInfo*info,int visibility){
mAttachInfo = info;
if(mOverlay)
@ -7001,6 +7004,7 @@ void View::setScaleX(float x){
invalidateViewProperty(true,false);
mRenderNode->setScaleX((x==.0f)?.00001f:x);//scale cant be zero
invalidateViewProperty(false,true);
invalidateParentIfNeededAndWasQuickRejected();
}
}
@ -7013,6 +7017,7 @@ void View::setScaleY(float y){
invalidateViewProperty(true,false);
mRenderNode->setScaleY((y==.0f)?.00001f:y);//scale cant be zero
invalidateViewProperty(false,true);
invalidateParentIfNeededAndWasQuickRejected();
}
}
@ -7284,6 +7289,7 @@ void View::AttachInfo::InvalidateInfo::recycle(){
}
View::AttachInfo::AttachInfo(Context*ctx){
mDisplay = nullptr;
mHardwareAccelerated =false;
mWindowVisibility = VISIBLE;
mHasWindowFocus = true;

View File

@ -9,6 +9,7 @@
#include <core/attributeset.h>
#include <core/context.h>
#include <core/intent.h>
#include <core/display.h>
#include <view/gravity.h>
#include <view/layoutparams.h>
#include <view/rendernode.h>
@ -207,7 +208,7 @@ public:
InvalidateInfo();
void recycle();
};
Display*mDisplay;
ViewGroup*mRootView;
bool mHardwareAccelerated;
float mApplicationScale;
@ -1100,6 +1101,7 @@ public:
void resetResolvedTextDirection();
void resetResolvedLayoutDirection();
virtual void resetResolvedPadding();
const Display* getDisplay()const;
void measure(int widthMeasureSpec, int heightMeasureSpec);
int getMeasuredWidth()const;
int getMeasuredWidthAndState()const;

View File

@ -454,7 +454,9 @@ void TextView::initView(){
mFontWeightAdjustment= INT_MAX;
mMarqueeFadeMode = MARQUEE_FADE_NORMAL;
mHorizontallyScrolling =false;
mNeedsAutoSizeText = false;
mEllipsize = Layout::ELLIPSIS_NONE;
mAutoSizeTextType = AUTO_SIZE_TEXT_TYPE_NONE;
mLayout = new Layout(18,1);
mHintLayout = new Layout(mLayout->getFontSize(),1);
mGravity = Gravity::NO_GRAVITY;
@ -644,8 +646,8 @@ void TextView::setText(const std::string&txt){
mCaretPos = ws.length()-1;
mLayout->setCaretPos(mCaretPos);
checkForRelayout();
mLayout->relayout();//use to fix getBaselineError for empty text
}
mLayout->relayout();//use to fix getBaselineError for empty text
}
const std::string TextView::getText()const{
@ -742,7 +744,7 @@ void TextView::checkForRelayout() {
/*makeNewLayout(want, hintWant, UNKNOWN_BORING, UNKNOWN_BORING,
mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight(),
false);*/
mLayout->relayout();
if (mEllipsize != Layout::ELLIPSIS_MARQUEE){//TextUtils.TruncateAt.MARQUEE) {
// In a fixed-height view, so use our new text layout.
if (mLayoutParams->height != LayoutParams::WRAP_CONTENT
@ -907,8 +909,16 @@ void TextView::setLineHeight(int h){
setLineSpacing(h-getLineHeight(),1.f);
}
bool TextView::isAutoSizeEnabled() const{
return supportsAutoSizeText() && mAutoSizeTextType != AUTO_SIZE_TEXT_TYPE_NONE;
}
bool TextView::supportsAutoSizeText()const {
return true;
}
void TextView::autoSizeText() {
if (1){//!isAutoSizeEnabled()) {
if (!isAutoSizeEnabled()) {
return;
}
@ -2129,9 +2139,8 @@ void TextView::onDraw(Canvas& canvas) {
int clipRight = getWidth() - compoundPaddingRight+ mScrollX;
int clipBottom= getHeight() + mScrollY - ((mScrollY == maxScrollY) ? 0 : extendedPaddingBottom);
LOGV_IF(dr!=nullptr,"%p rect=%d,%d-%d,%d ==>%d,%d-%d,%d paddings=%d,%d,%d,%d",this,
rect.left,rect.top,rect.width,rect.height, clipLeft, clipTop, clipRight-clipLeft, clipBottom-clipTop,
compoundPaddingLeft,compoundPaddingTop,compoundPaddingRight,compoundPaddingBottom);
rect.left,rect.top,rect.width,rect.height, clipLeft, clipTop, clipRight-clipLeft, clipBottom-clipTop,
compoundPaddingLeft,compoundPaddingTop,compoundPaddingRight,compoundPaddingBottom);
if (mShadowRadius != 0) {
clipLeft += std::min(.0f, mShadowDx - mShadowRadius);
@ -2140,8 +2149,8 @@ void TextView::onDraw(Canvas& canvas) {
clipTop += std::min(.0f, mShadowDy - mShadowRadius);
clipBottom+= std::max(.0f, mShadowDy + mShadowRadius);
}
//canvas.rectangle(clipLeft, clipTop, clipRight-clipLeft, clipBottom-clipTop);
//canvas.clip();
canvas.rectangle(clipLeft, clipTop, clipRight-clipLeft, clipBottom-clipTop);
canvas.clip();
int voffsetText = 0;
int voffsetCursor = 0;

View File

@ -31,6 +31,8 @@ private:
static constexpr int SERIF= 2;
static constexpr int MONOSPACE = 3;
public:
static constexpr int AUTO_SIZE_TEXT_TYPE_NONE = 0;
static constexpr int AUTO_SIZE_TEXT_TYPE_UNIFORM = 1;
class Drawables {
public:
enum{
@ -90,6 +92,7 @@ private:
int mDesiredHeightAtMeasure;
int mShadowColor;
int mDeferScroll;
int mAutoSizeTextType;
float mShadowRadius, mShadowDx, mShadowDy;
float mSpacingMult;
float mSpacingAdd;
@ -132,6 +135,7 @@ private:
int getBoxHeight(Layout* l);
void prepareDrawableForDisplay(Drawable*d);
bool isAutoSizeEnabled()const;
bool isMarqueeFadeEnabled();
bool canMarquee();
void startMarquee();
@ -163,6 +167,7 @@ protected:
void onDetachedFromWindowInternal()override;
bool verifyDrawable(Drawable* who)const override;
void onMeasure(int widthMeasureSpec, int heightMeasureSpec)override;
bool supportsAutoSizeText()const;
bool isPaddingOffsetRequired()override;
int getLeftPaddingOffset()override;
int getTopPaddingOffset()override;

View File

@ -1,14 +1,9 @@
#ifndef __CDLOG_H__
#define __CDLOG_H__
#include <stdio.h>
#include <sys/types.h>
typedef unsigned char BYTE;
#ifdef __cplusplus
extern "C" {
#endif
#endif
typedef enum{
LOG_VERBOSE,
@ -20,7 +15,7 @@ typedef enum{
}LogLevel;
void LogPrintf(int level,const char*tag,const char*func,int line,const char*format,...);
void LogDump (int level,const char*tag,const char*func,int line,const char*label,const BYTE*data,int len);
void LogDump (int level,const char*tag,const char*func,int line,const char*label,const unsigned char*data,int len);
void LogSetModuleLevel(const char*module,int level);
void LogParseModule(const char*module);
void LogParseModules(int argc,const char*argv[]);