diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-07-29 07:42:30 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2020-07-29 07:42:30 +0300 |
commit | 4deb72ba6ea6c055dff69d74669887f30ea01e54 (patch) | |
tree | ea9b9645b38367afabaa66637c15d9a1cd0c3374 /src/gmdocument.c | |
parent | d921021132367076cd2a5f120b3a49db6e29acf7 (diff) |
Showing and hiding image content
Diffstat (limited to 'src/gmdocument.c')
-rw-r--r-- | src/gmdocument.c | 89 |
1 files changed, 68 insertions, 21 deletions
diff --git a/src/gmdocument.c b/src/gmdocument.c index f8998c17..4a3f8e06 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -33,12 +33,16 @@ iDefineTypeConstruction(GmLink) | |||
33 | iDeclareType(GmImage) | 33 | iDeclareType(GmImage) |
34 | 34 | ||
35 | struct Impl_GmImage { | 35 | struct Impl_GmImage { |
36 | iInt2 size; | 36 | iInt2 size; |
37 | size_t numBytes; | ||
38 | iString mime; | ||
39 | iGmLinkId linkId; | ||
37 | SDL_Texture *texture; | 40 | SDL_Texture *texture; |
38 | iGmLinkId linkId; | ||
39 | }; | 41 | }; |
40 | 42 | ||
41 | void init_GmImage(iGmImage *d, const iBlock *data) { | 43 | void init_GmImage(iGmImage *d, const iBlock *data) { |
44 | init_String(&d->mime); | ||
45 | d->numBytes = size_Block(data); | ||
42 | uint8_t *imgData = stbi_load_from_memory( | 46 | uint8_t *imgData = stbi_load_from_memory( |
43 | constData_Block(data), size_Block(data), &d->size.x, &d->size.y, NULL, 4); | 47 | constData_Block(data), size_Block(data), &d->size.x, &d->size.y, NULL, 4); |
44 | if (!imgData) { | 48 | if (!imgData) { |
@@ -60,6 +64,7 @@ void init_GmImage(iGmImage *d, const iBlock *data) { | |||
60 | 64 | ||
61 | void deinit_GmImage(iGmImage *d) { | 65 | void deinit_GmImage(iGmImage *d) { |
62 | SDL_DestroyTexture(d->texture); | 66 | SDL_DestroyTexture(d->texture); |
67 | deinit_String(&d->mime); | ||
63 | } | 68 | } |
64 | 69 | ||
65 | iDefineTypeConstructionArgs(GmImage, (const iBlock *data), data) | 70 | iDefineTypeConstructionArgs(GmImage, (const iBlock *data), data) |
@@ -379,6 +384,7 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
379 | if (link->flags & remote_GmLinkFlag) { | 384 | if (link->flags & remote_GmLinkFlag) { |
380 | run.visBounds.pos.x -= gap_UI / 2; | 385 | run.visBounds.pos.x -= gap_UI / 2; |
381 | } | 386 | } |
387 | |||
382 | run.color = linkColor_GmDocument(d, run.linkId); | 388 | run.color = linkColor_GmDocument(d, run.linkId); |
383 | pushBack_Array(&d->layout, &run); | 389 | pushBack_Array(&d->layout, &run); |
384 | } | 390 | } |
@@ -429,18 +435,29 @@ static void doLayout_GmDocument_(iGmDocument *d) { | |||
429 | if (type == link_GmLineType) { | 435 | if (type == link_GmLineType) { |
430 | const size_t imgIndex = findLinkImage_GmDocument_(d, run.linkId); | 436 | const size_t imgIndex = findLinkImage_GmDocument_(d, run.linkId); |
431 | if (imgIndex != iInvalidPos) { | 437 | if (imgIndex != iInvalidPos) { |
438 | ((iGmLink *) at_PtrArray(&d->links, run.linkId - 1))->flags |= content_GmLinkFlag; | ||
432 | const iGmImage *img = constAt_PtrArray(&d->images, imgIndex); | 439 | const iGmImage *img = constAt_PtrArray(&d->images, imgIndex); |
440 | const int margin = 0.5f * lineHeight_Text(paragraph_FontId); | ||
441 | pos.y += margin; | ||
433 | run.bounds.pos = pos; | 442 | run.bounds.pos = pos; |
434 | run.bounds.size.x = d->size.x; | 443 | run.bounds.size.x = d->size.x; |
435 | const float aspect = (float) img->size.y / (float) img->size.x; | 444 | const float aspect = (float) img->size.y / (float) img->size.x; |
436 | run.bounds.size.y = d->size.x * aspect; | 445 | run.bounds.size.y = d->size.x * aspect; |
437 | run.visBounds = run.bounds; /* TODO: limit max height? */ | 446 | run.visBounds = run.bounds; |
447 | const iInt2 maxSize = mulf_I2(img->size, get_Window()->pixelRatio); | ||
448 | if (width_Rect(run.visBounds) > maxSize.x) { | ||
449 | /* Don't scale the image up. */ | ||
450 | run.visBounds.size.y = run.visBounds.size.y * maxSize.x / width_Rect(run.visBounds); | ||
451 | run.visBounds.size.x = img->size.x; | ||
452 | run.visBounds.pos.x = run.bounds.size.x / 2 - width_Rect(run.visBounds) / 2; | ||
453 | run.bounds.size.y = run.visBounds.size.y; | ||
454 | } | ||
438 | run.text = iNullRange; | 455 | run.text = iNullRange; |
439 | run.font = 0; | 456 | run.font = 0; |
440 | run.color = 0; | 457 | run.color = 0; |
441 | run.imageId = imgIndex + 1; | 458 | run.imageId = imgIndex + 1; |
442 | pushBack_Array(&d->layout, &run); | 459 | pushBack_Array(&d->layout, &run); |
443 | pos.y += run.bounds.size.y; | 460 | pos.y += run.bounds.size.y + margin; |
444 | } | 461 | } |
445 | } | 462 | } |
446 | prevType = type; | 463 | prevType = type; |
@@ -559,17 +576,26 @@ void setSource_GmDocument(iGmDocument *d, const iString *source, int width) { | |||
559 | } | 576 | } |
560 | 577 | ||
561 | void setImage_GmDocument(iGmDocument *d, iGmLinkId linkId, const iString *mime, const iBlock *data) { | 578 | void setImage_GmDocument(iGmDocument *d, iGmLinkId linkId, const iString *mime, const iBlock *data) { |
562 | /* TODO: check if we know this MIME type */ | 579 | if (!mime || !data) { |
563 | /* Load the image. */ { | 580 | iGmImage *img; |
564 | iGmImage *img = new_GmImage(data); | 581 | if (take_PtrArray(&d->images, findLinkImage_GmDocument_(d, linkId), (void **) &img)) { |
565 | img->linkId = linkId; /* TODO: use a hash? */ | ||
566 | if (img->texture) { | ||
567 | pushBack_PtrArray(&d->images, img); | ||
568 | } | ||
569 | else { | ||
570 | delete_GmImage(img); | 582 | delete_GmImage(img); |
571 | } | 583 | } |
572 | } | 584 | } |
585 | else { | ||
586 | /* TODO: check if we know this MIME type */ | ||
587 | /* Load the image. */ { | ||
588 | iGmImage *img = new_GmImage(data); | ||
589 | img->linkId = linkId; /* TODO: use a hash? */ | ||
590 | set_String(&img->mime, mime); | ||
591 | if (img->texture) { | ||
592 | pushBack_PtrArray(&d->images, img); | ||
593 | } | ||
594 | else { | ||
595 | delete_GmImage(img); | ||
596 | } | ||
597 | } | ||
598 | } | ||
573 | doLayout_GmDocument_(d); | 599 | doLayout_GmDocument_(d); |
574 | } | 600 | } |
575 | 601 | ||
@@ -649,25 +675,34 @@ const iGmRun *findRunAtLoc_GmDocument(const iGmDocument *d, const char *textCStr | |||
649 | return NULL; | 675 | return NULL; |
650 | } | 676 | } |
651 | 677 | ||
652 | const iString *linkUrl_GmDocument(const iGmDocument *d, iGmLinkId linkId) { | 678 | static const iGmLink *link_GmDocument_(const iGmDocument *d, iGmLinkId id) { |
653 | if (linkId > 0 && linkId <= size_PtrArray(&d->links)) { | 679 | if (id > 0 && id <= size_PtrArray(&d->links)) { |
654 | const iGmLink *link = constAt_PtrArray(&d->links, linkId - 1); | 680 | return constAt_PtrArray(&d->links, id - 1); |
655 | return &link->url; | ||
656 | } | 681 | } |
657 | return NULL; | 682 | return NULL; |
658 | } | 683 | } |
659 | 684 | ||
685 | const iString *linkUrl_GmDocument(const iGmDocument *d, iGmLinkId linkId) { | ||
686 | const iGmLink *link = link_GmDocument_(d, linkId); | ||
687 | return link ? &link->url : NULL; | ||
688 | } | ||
689 | |||
660 | int linkFlags_GmDocument(const iGmDocument *d, iGmLinkId linkId) { | 690 | int linkFlags_GmDocument(const iGmDocument *d, iGmLinkId linkId) { |
661 | if (linkId > 0 && linkId <= size_PtrArray(&d->links)) { | 691 | const iGmLink *link = link_GmDocument_(d, linkId); |
662 | const iGmLink *link = constAt_PtrArray(&d->links, linkId - 1); | 692 | return link ? link->flags : 0; |
663 | return link->flags; | 693 | } |
694 | |||
695 | uint16_t linkImage_GmDocument(const iGmDocument *d, iGmLinkId linkId) { | ||
696 | size_t index = findLinkImage_GmDocument_(d, linkId); | ||
697 | if (index != iInvalidPos) { | ||
698 | return index + 1; | ||
664 | } | 699 | } |
665 | return 0; | 700 | return 0; |
666 | } | 701 | } |
667 | 702 | ||
668 | enum iColorId linkColor_GmDocument(const iGmDocument *d, iGmLinkId linkId) { | 703 | enum iColorId linkColor_GmDocument(const iGmDocument *d, iGmLinkId linkId) { |
669 | if (linkId > 0 && linkId <= size_PtrArray(&d->links)) { | 704 | const iGmLink *link = link_GmDocument_(d, linkId); |
670 | const iGmLink *link = constAt_PtrArray(&d->links, linkId - 1); | 705 | if (link) { |
671 | return link->flags & http_GmLinkFlag | 706 | return link->flags & http_GmLinkFlag |
672 | ? orange_ColorId | 707 | ? orange_ColorId |
673 | : link->flags & gopher_GmLinkFlag ? blue_ColorId : cyan_ColorId; | 708 | : link->flags & gopher_GmLinkFlag ? blue_ColorId : cyan_ColorId; |
@@ -688,6 +723,18 @@ SDL_Texture *imageTexture_GmDocument(const iGmDocument *d, uint16_t imageId) { | |||
688 | return NULL; | 723 | return NULL; |
689 | } | 724 | } |
690 | 725 | ||
726 | void imageInfo_GmDocument(const iGmDocument *d, uint16_t imageId, iGmImageInfo *info_out) { | ||
727 | if (imageId > 0 && imageId <= size_PtrArray(&d->images)) { | ||
728 | const iGmImage *img = constAt_PtrArray(&d->images, imageId - 1); | ||
729 | info_out->size = img->size; | ||
730 | info_out->numBytes = img->numBytes; | ||
731 | info_out->mime = cstr_String(&img->mime); | ||
732 | } | ||
733 | else { | ||
734 | iZap(*info_out); | ||
735 | } | ||
736 | } | ||
737 | |||
691 | const iString *title_GmDocument(const iGmDocument *d) { | 738 | const iString *title_GmDocument(const iGmDocument *d) { |
692 | return &d->title; | 739 | return &d->title; |
693 | } | 740 | } |